C# XDoc Parse XML string - c#

I'm receiving data via an XML API and it's returning a node like the following:
<?xml version='1.0' encoding='utf-8' ?>
<location>
<name>ØL Shop</name>
</location>
I have no control over the response but I am trying to Load it into an XDocument in which it fails due to the invalid character.
Is there anything I can do to make this load properly? I want to keep the solution as general as possible because it is possible other invalid characters exist.
Thoughts?

You can use html parsers which are more tolerant to invalid inputs. For example; (using HtmlAgilityPack) this code works without any problem.
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(xml);
var name = doc.DocumentNode.Descendants("name").First().InnerText;

You cant use "&" symbol in XDocument.Parse input text. Replace it with "&" , like this
<?xml version='1.0' encoding='utf-8' ?>
<location>
<name>&Oslash;L Shop</name>
</location>

Why not just escape any invalid XML characters before you load the response into an XDocument? You could use a regex for this, should be relatively straight forward.
See escape invalid XML characters in C#

Related

How to add data after xml in c# and read the xml after?

I've got to create a file with xml header and after that i have to put normal data, smthing like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
Data of the file....
I've already got the code to write it to the file.
Code for that part:
private void setHeader(FileStream output, string nod2, string nod3, string )
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
doc.AppendChild(docNode);
XmlNode header = doc.CreateElement("Header");
doc.AppendChild(header);
XmlNode algorithm = doc.CreateElement("Algorithm");
algorithm.InnerText = "alg";
header.AppendChild(algorithm);
XmlNode node2= doc.CreateElement("nod2");
node2.InnerText = nod2;
header.AppendChild(node2);
XmlNode node3= doc.CreateElement("nod3");
node3.InnerText = nod3;
header.AppendChild(node3);
XmlNode node= doc.CreateElement("node");
header.AppendChild(node);
XmlNode user1 = doc.CreateElement("User");
node.AppendChild(user1);
XmlNode mail = doc.CreateElement("Email");
user1.AppendChild(mail);
XmlNode sessionKey = doc.CreateElement("SessionKey");
user1.AppendChild(sessionKey);
doc.Save(output);
}
It work's pretty well, but when i want to read it with
private void readHeader(FileStream input, out string algorithm)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
}
I got an error that when the "Data of the file..." starts: "Data on the root level is invalid".
Is there a way to do it with the data after whole xml, or have i to add the data as a node?
This can be done in multiple ways. In comments, you've indicated that the best way is unacceptable for reasons outside the scope of the discussion. For completeness, I'm going to put that one first anyway. Skip down to tl;dr for what I think you'll have to end up doing.
The preferred way to do this is to base64 encode the encrypted data and put it in a CDATA block:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<File>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
<Data><![CDATA[
ICAgIFhtbE5vZGUgYWxnb3JpdGhtID0gZG9jLkNyZWF0ZUVsZW1lbnQoIkFsZ29yaXRobSIpOw0K
ICAgIGFsZ29yaXRobS5Jbm5lclRleHQgPSAiYWxnIjsNCiAgICBoZWFkZXIuQXBwZW5kQ2hpbGQo
YWxnb3JpdGhtKTsNCiAgICBYbWxOb2RlIG5vZGUyPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMiIp
Ow0KICAgIG5vZGUyLklubmVyVGV4dCA9IG5vZDI7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5v
ZGUyKTsNCiAgICBYbWxOb2RlIG5vZGUzPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMyIpOw0KICAg
IG5vZGUzLklubmVyVGV4dCA9IG5vZDM7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5vZGUzKTs=
]]></Data>
</File>
That's the canonical answer to this question.
But you've told me that in your case, a requirement has been imposed that you can't do it that way.
Second choice is MIME (actually, MIME might be the first choice and the above might be the second). But I have a feeling they won't like MIME either.
Third choice, read the file as a string and search for some marker that's inserted between the XML and the binary data, something like a MIME boundary.
tl;dr
If they won't let you add such a marker to the file (and I bet they won't), search for the first occurrence of the substring "</Header>":
var xml = File.ReadAllText(filePath);
var endTag = "</Header>";
var headerXML = xml.Substring(0, xml.IndexOf(endTag) + endTag.Length);
var xdHeader = new XmlDocument();
xdHeader.LoadXml(headerXML);
I tested your code with writing directly to a file, doc.Save(#"c:\temp\test1.xml");
And loading from that file works fine. So there is nothing wrong with your xml document. Check your FileStream. Do you flush and close it properly? Does it have UTF-8 encoding?
What's the input in the node strings. Nothing that is invalid according to xml rules?
After a single root node, only comments and processor instructions can be written to xml. So, you can try to write your data in the comments.
It will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
...
</Header>
<!-- your data -->
<!-- another data -->
This method has limitations: your data may not contain -- (double-hyphen) and may not end in -.
But it is better, of course, not to do so.

Read XML with Arabic data embedded c#

I am trying to load an XML file that contains a mix of ASCII text and Arabic characters. Here is the top snippet:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ar_EG">
<context>
<message>
<location filename="ui/aboutdialog.cpp" line="90"/>
<source>You have </source>
<translation type="unfinished">يوجد لديك</translation>
</message>
<message>
<location filename="ui/aboutdialog.cpp" line="90"/>
<source> launches left</source>
<translation type="unfinished">عدد التشغيلات المتبقية</translation>
</message>
</context>
I want to load this up into a C# TreeView object, but I am having issues with loading into XDocument or XMLDocument.
Using this:
XDocument xd = XDocument.Load(File.ReadAllText(tbxTSFileName.Text));
or
XDocument xd = XDocument.Load(File.ReadAllText(tbxTSFileName.Text, Encoding.GetEncoding(874)));
Gives me a "Invalid URI: Uri string is too long" error.
Using this:
XmlDocument xd = new XmlDocument();
xd.Load(tbxTSFileName.Text);
Gives the error "Invalid character in the given encoding. Line 9 position 40".
Read the documentation for the method you're calling.
XDocument.Load takes a URL, not an XML string.
You want XDocument.Parse.
Your reader needs to use utf-8, as indicated in the document itself. Ideally, you would use an XML reader and it would take care of using the indicated encoding itself.

Display deserialized XML on ASP.NET page

How can I display XML output on ASP.NET page with XML tags?
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(jsonOutput, "root");
Console.WriteLine(doc.OuterXml);
I would like to get results on my page like this:
<root>
<id>108013515952807</id>
<posts>
<data>
<message>This...Game... http://www.youtube.com/watch?v=l8Xsex0pqXY</message>
<id>108013515952807_470604423027046</id>
<created_time>2013-05-15T20:02:31+0000</created_time>
</data>
<data>
<message>Streaming in a few minutes! http://www.youtube.com/watch?v=IYnHDT6V82k</message>
<id>108013515952807_470538076367014</id>
<created_time>2013-05-15T16:46:36+0000</created_time>
</data>
</posts>
</root>
I tried this but I get no XML tags like in example above.
Response.Write("<BR>" + doc.OuterXml);
If you just put XML onto a webpage, the browser thinks it might be HTML and "renders" it, which is why you can't see the tags. You need to encode the XML
You can use the method
Response.Write(Server.HtmlEncode(doc.OuterXml));
Try
XElement.Parse(request.OuterXml).ToString()
If you want prettified XML string,
refer to: What is the simplest way to get indented XML with line breaks from XmlDocument?

Reading contents of XML file without having to remove the XML declaration

I want to read all XML contents from a file. The code below only works when the XML declaration (<?xml version="1.0" encoding="UTF-8"?>) is removed. What is the best way to read the file without removing the XML declaration?
XmlTextReader reader = new XmlTextReader(#"c:\my path\a.xml");
reader.Read();
string rs = reader.ReadOuterXml();
Without removing the XML declaration, reader.ReadOuterXml() returns an empty string.
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.as.com/ver/ver.IClaimver/Car</a:Action>
<a:MessageID>urn:uuid:b22149b6-2e70-46aa-8b01-c2841c70c1c7</a:MessageID>
<ActivityId CorrelationId="16b385f3-34bd-45ff-ad13-8652baeaeb8a" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">04eb5b59-cd42-47c6-a946-d840a6cde42b</ActivityId>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost/ver.Web/ver2011.svc</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Car xmlns="http://www.as.com/ver">
<carApplication>
<HB_Base xsi:type="HB" xmlns="urn:core">
<Header>
<Advisor>
<AdvisorLocalAuthorityCode>11</AdvisorLocalAuthorityCode>
<AdvisorType>1</AdvisorType>
</Advisor>
</Header>
<General>
<ApplyForHB>yes</ApplyForHB>
<ApplyForCTB>yes</ApplyForCTB>
<ApplyForFSL>yes</ApplyForFSL>
<ConsentSupplied>no</ConsentSupplied>
<SupportingDocumentsSupplied>no</SupportingDocumentsSupplied>
</General>
</HB_Base>
</carApplication>
</Car>
</s:Body>
</s:Envelope>
Update
I know other methods that use NON-xml reader (e.g. by using File.ReadAllText()). But I need to know a way that uses an xml method.
There can be no text or whitespace before the <?xml ?> encoding declaration other than a BOM, and no text between the declaration and the root element other than line break.
Anything else is an invalid document.
UPDATE:
I think your expectation of XmlTextReader.read() is incorrect.
Each call to XmlTextReader.Read() steps through the next "token" in the XML document, one token at a time. "Token" means XML elements, whitespace, text, and XML encoding declaration.
Your call to reader.ReadOuterXML() is returning an empty string because the first token in your XML file is an XML declaration, and an XML declaration does not have an OuterXML.
Consider this code:
XmlTextReader reader = new XmlTextReader("test.xml");
reader.Read();
Console.WriteLine(reader.NodeType); // XMLDeclaration
reader.Read();
Console.WriteLine(reader.NodeType); // Whitespace
reader.Read();
Console.WriteLine(reader.NodeType); // Element
string rs = reader.ReadOuterXml();
The code above produces this output:
XmlDeclaration
Whitespace
Element
The first "token" is the XML declaration.
The second "token" encountered is the line break after the XML declaration.
The third "token" encountered is the <s:Envelope> element. From here a call to reader.ReadOuterXML() will return what I think you're expecting to see - the text of <s:Envelope> element, which is the entire soap packet.
If what you really want is to load the XML file into memory as objects, just call
var doc = XDocument.Load("test.xml")
and be done with the parsing in one fell swoop.
Unless you're working with an XML doc that is so monstrously huge that it won't fit in system memory, there's really not a lot of reason to go poking through the XML document one token at a time.
What about
XmlDocument doc=new XmlDocument;
doc.Load(#"c:\my path\a.xml");
//Now we have the XML document - convert it to a String
//There are many ways to do this, one should be:
StringWriter sw=new StringWriter();
doc.Save(sw);
String finalresult=sw.ToString();
EDIT: I'm assuming you mean you actually have text between the document declaration and the root element. If that's not the case, please clarify.
Without removing the extra text, it's simply an invalid XML file. I wouldn't expect it to work. You don't have an XML file - you have something a bit like an XML file, but with extraneous stuff before the root element.
IMHO you can't read this file. It's because there's a plain text before the root element <s:Envelope> which makes whole document invalid.
You're parsing an XML document as XML just to obtain the source text? Why?
If you really want to do that then:
string rs;
using(var rdr = new StreamReader(#"c:\my path\a.xml"))
rs = rdr.ReadToEnd();
Will work, but I'm really not sure that is what you actually want. This pretty much ignores that it's XML and just reads the text. Useful for some things, but not a lot.

How to generate XML on MonoTouch?

I need to generate XML on MonoTouch application ? How i can create like this,
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
...
</root>
I need to post the XML to web service as string format. And again I want to parse the response data. Response data also XML format string. I done it in j2me applications. But I don't know how to do this on MonoTouch? Anyone tell me How to do this?
My favorite API these days is the System.Xml.Linq API, look at the documentation and samples here:
http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.aspx
For what you want, this is very easy:
var s = new XDocument () {
new XElement ("root")
};
Console.WriteLine ("The XML is: {0}", s.ToString ());
You can create the XML by using the XmlWriter class.
The easiest way to parse XML would be to use LINQ.

Categories

Resources