Error trying to read an XML Document(C#)? - c#

I have the following XML that I am trying to "load" into an XmlDocument object:Link to XML File
I have the following method piece of code to load the XML document:
public XmlDocument getDirections()
{
XmlTextReader xmlReader;
XmlDocument xmlResponse = new XmlDocument();
StringBuilder xmlResponseString = new StringBuilder();
xmlReader = new XmlTextReader(getRequestURL()); //getRequestURL gives the URL for XML doucument
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
xmlResponseString.Append(xmlReader.ReadInnerXml());
}
}
xmlResponse.LoadXml(xmlResponseString.ToString());
return xmlResponse;
}
When I run the code, I get the following error:
An unhandled exception of type 'System.Xml.XmlException' occurred in System.Xml.dll
Additional information: There are multiple root elements. Line 3, position 3.
I figured this happens because the XML document have multiple route objects but I don't know how to fix it. Any help would be appreciated !

The line where it says:
Additional information: There are multiple root elements. Line 3, position 3.
This is your clue.
Properly formatted XML will have 1 root element.
Ex.
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
See for a further explanation: http://www.w3schools.com/xml/xml_syntax.asp

What's the point of doing it that way? Use the built in functionality for getting Xml from a Url:
var str = #"https://maps.googleapis.com/maps/api/directions/xml?origin=Jamaica,%20NY%2011418&destination=Hunter%20College%20Park%20Avenue%20New%20York&mode=&alternatives=true&key=AIzaSyB8G9omVUu6a_OQCrRM-QItdwk-Hxq__mg";
var doc = new XmlDocument();
doc.Load(str);
//or
var xdoc = XDocument.Load(str);
I would look into Linq to Xml (XDocument) over XmlDocument. It's a lot easier to work with.

You can use following snippet to load xml.
public XmlDocument getDirections()
{
XmlTextReader xmlReader;
XmlDocument xmlResponse = new XmlDocument();
StringBuilder xmlResponseString = new StringBuilder();
HttpWebRequest request =HttpWebRequest.Create(getRequestURL());
using(HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
if (response.StatusCode == HttpStatusCode.OK)
{
using (var responseStream = response.GetResponseStream())
{
xmlResponse.Load(responseStream);
}
}
}
xmlResponse.LoadXml(xmlResponseString.ToString());
return xmlResponse;
}

I came across a similar incident when trying to read an Xml using the XmlReader.
My code:
using (XmlReader reader = XmlReader.Create(new StringReader(filesContent)))
{
while (reader.Read()) //<--- This is where the exception was caught
{
// Do stuff here
}
}
The exception caught:
An unhandled exception of type 'System.Xml.XmlException' occurred in
System.Xml.dll
Additional information: There are multiple root elements. Line X,
position Y.
Note: The information regarding the location of the line and position which were provided in the exception were not the actual line or the position in the xml file content where my additional root was, making this a bit misleading.
A properly formatted xml file should contain only ONE root. As such:
<?xml version="1.0" encoding="UTF-8" ?>
<root1>
<child1>
<subchild1>.....</subchild1>
</child1>
</root1>
In my case the exception was being thrown because my xml file contained 2 roots.
<?xml version="1.0" encoding="UTF-8" ?>
<root1>
<child1>
<subchild1>.....</subchild1>
</child1>
</root1>
<root2>
<child1>
<subchild1>.....</subchild1>
<subchild2>.....</subchild2>
</child1>
<child2>
<subchild1>.....</subchild1>
</child2>
</root2>
This could easily be fixed by adding some 'parentroot' to the file, making the 2 roots nest under the new parent root as such
<?xml version="1.0" encoding="UTF-8" ?>
<parnetroot>
<root1>
<child>
<subchild>.....</subchild>
</child>
</root1>
<root2>
<child1>
<subchild1>.....</subchild1>
<subchild2>.....</subchild2>
</child1>
<child2>
<subchild1>.....</subchild1>
</child2>
</root2>
</parnetroot>

Related

xml data always being created as CDATA and not PCDATA

I wrote a web service with C# , and i want one of his methods to return an XML.
i've managed to do so , but all the data is being tagged as CDATA and not being parsed. its not what i am looking for.
this is my code :
[WebMethod(EnableSession = true, Description = "Returns the safe activities for the required days period in XML")]
public string GetSafeActivitiesXML(string safename, int days, string FileName)
{
string returnErrorCode = "001";
try
{
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true
//IndentChars = " ",
//NewLineChars = "\n",
//NewLineHandling = NewLineHandling.None,
//Encoding = System.Text.Encoding.UTF8
};
StringWriter sb = new StringWriter();
XmlWriter writer = XmlWriter.Create(sb,settings);
writer.WriteStartDocument();
writer.WriteStartElement("GetSafeActivitiesResult", "");
int lineCouner = 0;
if (safeActivities.Count > 0)
{
writer.WriteStartElement("ListOfStrings", "");
foreach (ActivityLogRecord activity in safeActivities)
{
writer.WriteStartElement("string");
writer.WriteElementString("outFileName", (activity.Info1.Substring(activity.Info1.LastIndexOf("\\")+1)));
writer.WriteElementString("activityTmStamp", activity.Time.ToString());
writer.WriteElementString("userName", activity.UserName);
writer.WriteElementString("ActionID", activityCode);
writer.WriteElementString("direction", direction);
writer.WriteElementString("path", activity.Info1);
writer.WriteEndElement();
lineCouner++;
}
}
writer.WriteEndElement();
}
writer.WriteStartElement("retunCode");
writer.WriteString((lineCouner > 0) ? "0" : "2");
writer.WriteEndElement();
writer.WriteStartElement("retunMessage");
writer.WriteString((lineCouner > 0) ? "תקין" : "אין נתונים");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
XmlDocument xmlOut = new XmlDocument();
xmlOut.LoadXml(sb.ToString());
writer.Close();
//xmlOut.Save(xxx);
string finalOutput = sb.ToString();
finalOutput.Replace("![CDATA[", "").Replace("]]", "");
return sb.ToString();
}
catch (Exception ex)
{
this.LogWrite("GetSafeActivities", string.Format("Operation has failed: {0}, internal errorcode: {1}", ex.Message,returnErrorCode), Session.SessionID, true);
return string.Format("<ReturnCode>{0}</ReturnCode><ReturnMSG>{1}</ReturnMSG>", "שגוי", ex.Message) ;
}
}
This is an example for the current output:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetSafeActivitiesXMLResponse xmlns="http://www.securenet.co.il">
<GetSafeActivitiesXMLResult><![CDATA[<?xml version="1.0" encoding="utf-16"?>
<GetSafeActivitiesResult>
<ListOfStrings>
<string>
<outFileName>code-xmp-tmp.txt</outFileName>
<activityTmStamp>21/06/2015 10:58:38</activityTmStamp>
<userName>naaman</userName>
<ActionID>קובץ אוחסן בכספת</ActionID>
<direction>Unknown</direction>
<path>Root\fgdf\code-xmp-tmp.txt</path>
</string>
</ListOfStrings>
<retunCode>0</retunCode>
<retunMessage>תקין</retunMessage>
</GetSafeActivitiesResult>]]></GetSafeActivitiesXMLResult>
</GetSafeActivitiesXMLResponse>
</soap:Body>
This is what i want to achieve:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetSafeActivitiesXMLResponse xmlns="http://www.securenet.co.il">
<GetSafeActivitiesXMLResult><?xml version="1.0" encoding="utf-16"?>
<GetSafeActivitiesResult>
<ListOfStrings>
<string>
<outFileName>code-xmp-tmp.txt</outFileName>
<activityTmStamp>21/06/2015 10:58:38</activityTmStamp>
<userName>naaman</userName>
<ActionID>קובץ אוחסן בכספת</ActionID>
<direction>Unknown</direction>
<path>Root\fgdf\code-xmp-tmp.txt</path>
</string>
</ListOfStrings>
<retunCode>0</retunCode>
<retunMessage>תקין</retunMessage>
</GetSafeActivitiesResult></GetSafeActivitiesXMLResult>
</GetSafeActivitiesXMLResponse>
</soap:Body>
so my question really is , how to get rid of the CDATA tag, and why is it there on the first place.
i'm new to xml, so please be patient.
The output you want to achieve is XML that is not well-formed: you're essentially trying to nest an XML document, complete with an XML declaration (i.e. <?xml version="1.0" encoding="utf-16"?>), as literal character data within an XML document (or fragment) -- this is not a legal construct.
The proper way to include an XML document, or any text which would be recognized as markup, within another XML document (element) is to basically escape it by using a CDATA section so that it is not parsed as markup. And that is exactly what the web service/SOAP infrastructure is doing for you.
If it didn't do that and your XML text became parsed data (PCDATA) like you want, the consuming parser would throw an exception or return an error because your web service response XML would not be well-formed.
the method returned a String type, and that was the problem.
i changed the return type to XmlDocument, and now its all honey and nuts.

Query in document with inline default namespace

I'm trying/struggling to query the getCompanyListResponse-Tag(every tag above that one works fine with the namespacemanager and the "soap" prefix) within the following XML structure:
<?xml version=”1.0” encoding=”UTF-8”?>
<soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Header />
<soap:Body>
<getCompanyListResponse xmlns=”http://test.org/schema”>
<company>
<id>12345</id>
<address>
<role>LOCATION</role>
</adress>
</company>
</getCompanyListResponse>
</soap:Body>
</soap:Envelope>
Unfortunately I can't change any XML,because the XML is a response of a webservice, I'm not able to influence.
Sadly, adding the default namespace to the XMLNamespacemanager didn't work.
I didn't find any sufficient answer on how to use the local-name function .
Stream responseStream = response.GetResponseStream();
XPathDocument compDoc = new XPathDocument(responseStream);
XPathNavigator root = compDoc.CreateNavigator();
XmlNamespaceManager resolver = new XmlNamespaceManager(root.NameTable);
resolver.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
resolver.AddNamespace(String.Empty, "http://test.org/schema");
resolver.AddNamespace("null", "http://test.org/schema");
root.MoveToFirstChild();
XPathNavigator body = root.SelectSingleNode("[/local-name()='soap:Envelope/soap:Body/getCompanyListResponse']", resolver);
With the last line in the code right above I get the Exception: "the Expression must result in a node-set"(or close to that, since I use visual studio in German, is this my attempt of translation)
You need to use a prefix in your path to address elements in a default namespace:
XPathDocument compDoc = new XPathDocument(responseStream);
XPathNavigator root = compDoc.CreateNavigator();
XmlNamespaceManager resolver = new XmlNamespaceManager(root.NameTable);
resolver.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
resolver.AddNamespace("ts", "http://test.org/schema");
XPathNavigator comp = root.SelectSingleNode("/soap:Envelope/soap:Body//ts:company", resolver);
string id = comp.SelectSingleNode("ts:id").Value;
And your attempt with local-name() in a predicate without a step is also not going to work but not necessary anyway.
It seems to me you're trying to read an XML stream, but if I'm not understanding you I apologize.
XmlReader seems to me its the right tool for the job.
XmlReader http://msdn.microsoft.com/en-us/library/system.xml.xmlreader(v=vs.110).aspx
var reader = XmlReader.Create(responseStream);
var xmlnsString = string.Empty;
string id;
while(reader.Read()){
if(reader.IsStartElement()){
switch(reader.Name){
case("getCompanyListResponse") : xmlnsString = reader.GetAttribute("xmlns");
//list any name of a node you want to work on here
case("id") : id = reader.ReadString();
default: break;
}
}
}

Editing an XML file in C#; SelectSingleNode returns null

I'm trying to find existing content within an XML file and change it by making use of the SelectSingleNode command. However, all I get is a NullReferenceException. Maybe I'm just not getting how the file path works with this particular command, but I've tried many variants I've found online but to no avail. Could anyone help me figure out what I'm doing wrong?
Here's the script.
public void saveStuff()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"Worlds\WorldData.xml"); //loads the file just fine
XmlNode node = xmlDoc.SelectSingleNode("//World[#ID='002']/Name"); //node = null
node.Value = "New Name"; //NullReferenceException was unhandled
xmlDoc.Save(#"Worlds\example.xml");
}
And here's a sample of my XML file.
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<World ID="001">
<Name>
TinyWorld
</Name>
<Size>
4x4
</Size>
<Tiles>
000,000,000,001,
000,000,000,001,
001,001,004,001,
001,001,001,001,
</Tiles>
</World>
<World ID="002">
<Name>
MicroWorld
</Name>
<Size>
2x2
</Size>
<Tiles>
000,000,
001,001,
</Tiles>
</World>
</XnaContent>
Instead:
public void saveStuff()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"Worlds\WorldData.xml");
XmlElement root = xmlDoc.DocumentElement;
XmlNode node = root.SelectSingleNode("//World[#ID='002']/Name");
node.Value = "New Name";
xmlDoc.Save(#"Worlds\example.xml");
}
You were selecting using the // xpath, but at that moment, no context. That syntax is relative to the current node.

Preserve xml formatting using XmlDocument

I am using XmlDocument to work with xml
How do I save my "XmlDocument" with my current formatting?
Current formatting:
<?xml version="1.0" encoding="utf-8"?>
<root>
<element></element>
</root>
Code:
XmlDocument testDoc = new XmlDocument();
testDoc.Load(#"C:\Test.xml");
**(do reading/writing using only XmlDocument methods)**
testDoc.Save(#"C:\Test.xml");
There is a similar topic:
XmlDocument class is removing formatting, c#, .NET
The accepted answer is PreserveWhiteSpace = true, which in reality removes all whitespaces instead of preserving them.
Example:
Code:
XmlDocument testDoc = new XmlDocument();
testDoc.Load(#"C:\Test.xml");
testDoc.PreserveWhitespace = true;
testDoc.Save(#"C:\Test.xml");
Result:
<?xml version="1.0" encoding="utf-8"?><root><element></element></root>
Setting PreserveWhitespace to true works for me - but you've got to do it before loading so that the whitespace doesn't get thrown away at load time:
using System;
using System.Xml;
class Test
{
static void Main()
{
XmlDocument testDoc = new XmlDocument();
testDoc.PreserveWhitespace = true;
testDoc.Load("Test.xml");
testDoc.Save("Output.xml");
}
}
I've just tried that, and the whitespace was preserved.
Umm. I'm seeing whitespace being preserved when using PreserveWhiteSpace=true. Perhaps it was false when you loaded?
var xmlStr = #"<?xml version=""1.0"" encoding=""utf-8""?>
<root>
<element></element>
</root>";
var xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(xmlStr);
xmlDoc.Save(Console.Out);
Shows:
<?xml version="1.0" encoding="utf-16"?>
<root>
<element></element>
</root>
use preservewhitespace before you load. It will keep formatting same
like above
var xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(xmlStr);
if you will use it after loading. it will kill white spaces in between

Add a Text line in xml on a particular location?

How can I insert the following stylesheet information into my existing xml file which is created using C#?
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
Or.... Can I add this line at the time of creation of the new XML file?
Edit:
I tried to achieve the above using XmlSerialier (hit and trial), something like this:
// assumes 'XML' file exists.
XmlDocument doc = new XmlDocument();
XElement dataElements = XElement.Load("_fileName.xml");
XmlSerializer xs = new XmlSerializer(typeof(Parents));
var ms = new MemoryStream();
xs.Serialize(ms, parents);
ms.Seek(0, SeekOrigin.Begin); // rewind stream to beginning
doc.Load(ms);
XmlProcessingInstruction pi;
string data = "type=\"text/xsl\" href=\"_fileName.xsl\"";
pi = doc.CreateProcessingInstruction("xml-stylesheet", data);
doc.InsertBefore(pi, doc.DocumentElement); // insert before root
doc.DocumentElement.Attributes.RemoveAll(); // remove namespaces
But the output xml is getting corrupted:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
<parents />
Whereas the desired output is something like:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
<parents>
<parent>
<Child1>
<child2>
</parent>
</parents>
Did this help to understand what's my problem???
You didn't answer the question.. "what lib do you use".
Although I advise:
XDocument
if you would use it you could do something like:
XDocument document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
document.Add(new XProcessingInstruction(
"xml-stylesheet", "type=\"text/xsl\" href=\"_fileName.xsl\""));
//and then your actual document...
document.Add(
new XElement("parent",
new XElement("child1"),
new XElement("child2")
)
);
EDIT:
Ok So you could do it like:
XDocument document = XDocument.Load("file");
document.AddFirst(new XProcessingInstruction(
"xml-stylesheet", "type=\"text/xsl\" href=\"LogStyle.xsl\""));
Is this what you're looking for?

Categories

Resources