Xml root node not closed - c#

I'm using xmlwriter to create an xml document. The xml document looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<ExceptionsList />
How can i prevent the /> and appropriately end the root node?
Because of this, i can't append anything to the root node.
My code for creating the xml file looks like this:
string formatDate = DateTime.Now.ToString("d-MMM-yyyy");
XmlTextWriter xmlWriter = new XmlTextWriter(xmlfileName, Encoding.UTF8);
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.Indentation = 3;
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("ExceptionsList"); // ExceptionsList (Root) Element
xmlWriter.WriteEndElement(); // End of ExceptionsList (Root) Element
xmlWriter.WriteEndDocument();
xmlWriter.Flush();
xmlWriter.Close();
And I append to the root node like this:
XDocument xml = XDocument.Load(xmlFileName);
XElement root = xml.Root;
root.Add(new XElement("Exception",
new XElement("Exception Type", exceptionType),
new XElement("Exception Message", exceptionMessage),
new XElement("InnerException", innerException),
new XElement("Comment", comment)));
xml.Save(xmlFileName);
This gives me a stackoverflow at runtime error too.
Any help would be appreciated.
Thanks in advance!

Your code is right, and you don't need to change how your ExceptionsList element is closed.
xmlWriter.WriteStartElement("ExceptionsList"); // ExceptionsList (Root) Element
xmlWriter.WriteStartElement("Exception"); // An Exception element
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement(); // End of ExceptionsList (Root) Element
In your second snippet, you need to remove those white spaces from element name, as XML specification forbid that and add your elements into your XDocument instance, like this:
XDocument xml = new XDocument();
xml.Add(new XElement("Exception",
new XElement("ExceptionType", "Exception"),
new XElement("ExceptionMessage",
new XElement("InnerException", "innerException")),
new XComment("some comment")));
xml.Save("sample2.xml");

I believe the problem is here:
new XElement("Exception Type", exceptionType),
new XElement("Exception Message", exceptionMessage),
Neither Exception Type nor Exception Mesage is a valid name for an xml element. Then of course, if you use this (doomed) method to log the error... stack overflow.

Related

XElement.Load() and "undeclared prefix" exception

I'm trying to load xml file using Xelement.Load() method and in case of some files, I get "ditaarch" is an undeclared prefix exception. The content of such troublesome xml's are similar to this simplified version:
<?xml version="1.0" encoding="UTF-8"?>
<concept ditaarch:DITAArchVersion="1.3">
<title>Test Title</title>
<menucascade>
<uicontrol>text</uicontrol>
<uicontrol/>
</menucascade>
</concept>
I've tried to follow suggestions to manually add or ignore "ditaarch" namespace using xml namespace manager:
using (XmlReader reader = XmlReader.Create(#"C:\test\example.xml"))
{
NameTable nameTable = new NameTable();
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(nameTable);
nameSpaceManager.AddNamespace("ditaarch", "");
XmlParserContext parserContext = new XmlParserContext(null, nameSpaceManager, null, XmlSpace.None);
XElement elem = XElement.Load(reader);
}
But it leads to same exception as before. Most probably the solution is trivial but I just can't see it :(
If anyone would be able to point me in the right direction, I would be most grateful.
The presented markup is not namespace well-formed XML so I don't think XElement or XDocument is an option as it doesn't support colons in names. You can parse it with a legacy new XmlTextReader("foo.xml") { Namespaces = false } however.
And you could use XmlDocument instead of XDocument or XElement and check for any empty elements with e.g.
XmlDocument doc = new XmlDocument();
using (XmlReader xr = new XmlTextReader("example.xml") { Namespaces = false })
{
doc.Load(xr);
}
Console.WriteLine("Number of empty elements: {0}", doc.SelectNodes("//*[not(*)][not(normalize-space())]").Count);

Parsing wrongly formatted XML-SOAP with C#

I have malformed XML (SOAP) file which I need to parse. The issue is that XML doesn't have proper header tags.
I've tried to parse file with XDocument and XmlDocument but neither has worked. XML starts from the line 30, so maybe there is some way to skip those lines before file is read by XML parser?
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:eb="http://www.oasis-open.org/committees/ebxml-msg/schema/msg-header-2_0.xsd">
<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="Finvoice.xsl"?>
<GGVersion="2.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="a.xsd">
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlReader r = XmlReader.Create(file.FullName, settings);
XmlDocument xDoc = new XmlDocument();
xDoc.PreserveWhitespace = true;
xDoc.LoadXml("<xml/>");
xDoc.DocumentElement.CreateNavigator().AppendChild(r);
XmlNamespaceManager manager = new XmlNamespaceManager(xDoc.NameTable);
Once trying to parse I get: Unexpected xml declaration. The xml declaration must be the first node in the document ....
If I understand you correctly, then the data you are looking for starts after the SOAP envelope. There is no garbage/unnessescary contents after the data you are looking for.
The SOAP header does not start with the XML declaration (<?xml version=, etc).
Looking for the start of the document
A simple solution is to find the start of the XML document (the data you are looking for), and chop away everything before that.
var startOfRealDocumentMarker = "<?xml version=\"1.0\"";
var startIndex = dirtyXmlString.IndexOf(startOfRealDocumentMarker);
if(startIndex == -1) {
throw new Exception("Start of XML not found. Now what?");
}
var cleanXmlString = dirtyXmlString.Substring(startIndex);
If the SOAP header also has an XML declaration, you could look for the end-tag of the SOAP envelope instead. Or you could start looking for the declaration at the 2nd character, so you would skip over the first one.
This is obviously not a fool-proof solution that will work in every case. But maybe it will work in all of your cases?
Skipping lines
If you're sure it will work to always start reading from line 30 of the input file, you can use this method instead.
XmlDocument xDoc = new XmlDocument();
using (var rdr = new StreamReader(pathToXmlFile))
{
// Skip until reader is positioned at start of line 30
for (var i = 0; i < 29; ++i)
{
rdr.ReadLine();
}
// Load document from current position of reader
xDoc.Load(rdr);
}

"Root element is missing" exception given when trying to parse XML file

I'm trying to set up parsing for a test XML generated with ksoap2 in Android:
<?xml version="1.0" encoding="utf-8"?>
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<v:SOAPBODY>
<v:INFO i:type="v:INFO">
<v:LAITETUNNUS i:type="d:string">EI_TUNNUSTA</v:LAITETUNNUS>
</v:INFO>
<v:TOIMINNOT i:type="v:TOIMINNOT">
<v:TOIMINTA i:type="d:string">ASETUKSET_HAKU</v:TOIMINTA>
</v:TOIMINNOT>
<v:SISALTO i:type="v:SISALTO">
<v:KUVA i:type="d:string">AGFAFDGFDGFG</v:KUVA>
<v:MITTAUS i:type="d:string">12,42,12,4,53,12</v:MITTAUS>
</v:SISALTO>
</v:SOAPBODY>
</v:Body>
</v:Envelope>
But seemingly i can't parse it in any way. The exception is always that "Root element is not found" even when it goes through XML-validators like the one at w3schools. If i'm correct the contents of the body shouldn't be an issue when the problem is with root element.
The test code for parsing i try to use in C# is:
using (StreamReader streamreader = new StreamReader(Context.Request.InputStream))
{
try
{
XDocument xmlInput = new XDocument();
streamreader.BaseStream.Position = 0;
string tmp = streamreader.ReadToEnd();
var xmlreader = XmlReader.Create(streamreader.BaseStream);
xmlInput = XDocument.Parse(tmp);
xmlInput = XDocument.Load(xmlreader);
catch (Exception e)
{ }
where the xmlInput = XDocument.Parse(tmp); does indeed parse it to a XDocument, not a navigable one, though. Then xmlInput = XDocument.Load(xmlreader); throws the exception for not having a root element. I'm completely at loss here because i managed to parse and navigate the almost same xml with XMLDocument and XDocument classes before, and i fear i made some changes i didn't notice.
Thanks in advance.
Update: Here's the string tmp as requested :
"<?xml version=\"1.0\" encoding=\"utf-8\"?><v:Envelope xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\" xmlns:c=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:v=\"http://schemas.xmlsoap.org/soap/envelope/\"><v:Header /><v:Body><v:SOAPBODY><v:INFO i:type=\"v:INFO\"><v:LAITETUNNUS i:type=\"d:string\">EI_TUNNUSTA</v:LAITETUNNUS></v:INFO><v:TOIMINNOT i:type=\"v:TOIMINNOT\"><v:TOIMINTA i:type=\"d:string\">ASETUKSET_HAKU</v:TOIMINTA></v:TOIMINNOT><v:SISALTO i:type=\"v:SISALTO\"><v:KUVA i:type=\"d:string\">AGFAFDGFDGFG</v:KUVA><v:MITTAUS i:type=\"d:string\">12,42,12,4,53,12</v:MITTAUS></v:SISALTO></v:SOAPBODY></v:Body></v:Envelope>\r\n"
Update: Even with XDocument.Load(new StreamReader(Context.Request.InputStream, Encoding.UTF8)); the parsing will fail.
I believe you've read to the end of the stream once already, you need to reset the position in the stream again. see: "Root element is missing" error but I have a root element

Can not save string / node to XML WP8

I am reading the contents of an xml file perfectly into a longlistselector with tap events attached. All working great. The file sits in the main assets folder of the project.
Now i would also like to add strings/ nodes to my simple XML, but for some reason i can't find the right syntax to save it to the file.
My xml file looks like:
<?xml version="1.0" encoding="utf-8" ?>
<phrases>
<item><name>What is your name?</name></item>
<item><name>How old are you?</name></item>
</phrases>
Now I tried the following inside of a click event of a button:
XDocument xDoc = XDocument.Load("phrases.xml");
var contactsElement = new XElement("item",
new XElement("name", "blalllllaaaallaala")));
xDoc.Add(contactsElement);
xDoc.Save("phrases.xml");
VS2013 tells me that the xDoc.Save("phrases.xml") has invalid arguments. When i read from that file i provide the same path, so i dont understand what is expected here? Please give some suggestions.
Just try out with this snippet...
// load original XML from the stream
XDocument loadedData = XDocument.Load(stream);
// create a new parent XML structure (new root) and load the original nodes
var newXml = new XDocument(new XElement("Histories"));
newXml.Root.Add(loadedData.Root);
// create the new node
var contactsElement = new XElement("item",
new XElement("name", "blalllllaaaallaala")));
NewNode.Add(contactsElement);
// add the new node
newXml.Root.Add(NewNode);
// save the stream
newXml.Save(stream);
For more have a look here too.

need to add comments in an existing xml document

I need to add comments in an existing xml document.a sample xml is shown below i need to write code in c#. XML serialization was used to generate this xml
any help would be great...
thanks in advance
<?xml version="1.0" encoding="utf-8"?>
<Person>
<Name>Job</Name>
<Address>10dcalp</Address>
<Age>12</Age>
</Person>
Try it like this:
string input = #"<?xml version=""1.0"" encoding=""utf-8""?><Person><Name>Job</Name><Address>10dcalp</Address><Age>12</Age></Person>";
XDocument doc = XDocument.Parse(input);
XElement age = doc.Root.Element("Age");
XComment comm = new XComment("This is comment before Age");
age.AddBeforeSelf(comm);
This code gets the document, finds the element named "Age" which is expected to be under the root element ("Person") and adds comment before it.
You can use XmlWriter to write the comment in following way:
MemoryStream stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream);
writer.WriteStartDocument();
writer.WriteComment("Add comment here");
Now, you serialize XmlWriter instance through your serializer.

Categories