Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

parsing XML with ampersand

Tags:

I have a string which contains XML, I just want to parse it into Xelement, but it has an ampersand. I still have a problem parseing it with HtmlDecode. Any suggestions?

string test = " <MyXML><SubXML><XmlEntry Element="test" value="wow&" /></SubXML></MyXML>"; 

XElement.Parse(HttpUtility.HtmlDecode(test));

I also added these methods to replace those characters, but I am still getting XMLException.

string encodedXml = test.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("'", "&apos;");
XElement myXML = XElement.Parse(encodedXml);

t or Even tried it with this:

string newContent=  SecurityElement.Escape(test);
XElement myXML = XElement.Parse(newContent);
like image 593
paradisonoir Avatar asked Sep 24 '09 19:09

paradisonoir


People also ask

Can I use ampersand in XML?

Yes, the ampersand symbol may be used in Food Trust XML files as long as it is in XML Predefined Entity format. XML has a few special characters or symbols which are not available to be typed directly from the keyboard.

How do you pass ampersand in XML string?

xml version="1.0"?> An ampersand a character reference can also be escaped as &amp; in element content of XML.

Does ampersand need to be escaped in XML?

The ampersand & character must be escaped. The greater than and less than characters do no have to be escaped but its good practice to do it. The double quotes in the data must be escaped.

How do I parse a special character in XML?

To include special characters inside XML files you must use the numeric character reference instead of that character. The numeric character reference must be UTF-8 because the supported encoding for XML files is defined in the prolog as encoding="UTF-8" and should not be changed.


2 Answers

Ideally the XML is escaped properly prior to your code consuming it. If this is beyond your control you could write a regex. Do not use the String.Replace method unless you're absolutely sure the values do not contain other escaped items.

For example, "wow&amp;".Replace("&", "&amp;") results in wow&amp;amp; which is clearly undesirable.

Regex.Replace can give you more control to avoid this scenario, and can be written to only match "&" symbols that are not part of other characters, such as &lt;, something like:

string result = Regex.Replace(test, "&(?!(amp|apos|quot|lt|gt);)", "&amp;");

The above works, but admittedly it doesn't cover the variety of other characters that start with an ampersand, such as &nbsp; and the list can grow.

A more flexible approach would be to decode the content of the value attribute, then re-encode it. If you have value="&wow&amp;" the decode process would return "&wow&" then re-encoding it would return "&amp;wow&amp;", which is desirable. To pull this off you could use this:

string result = Regex.Replace(test, @"value=\""(.*?)\""", m => "value=\"" +
    HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups[1].Value)) +
    "\"");
var doc = XElement.Parse(result);

Bear in mind that the above regex only targets the contents of the value attribute. If there are other areas in the XML structure that suffer from the same issue then it can be tweaked to match them and replace their content in a similar fashion.


EDIT: updated solution that should handle content between tags as well as anything between double quotes. Be sure to test this thoroughly. Attempting to manipulate XML/HTML tags with regex is not favorable as it can be error prone and over-complicated. Your case is somewhat special since you need to sanitize it first in order to make use of it.
string pattern = "(?<start>>)(?<content>.+?(?<!>))(?<end><)|(?<start>\")(?<content>.+?)(?<end>\")";
string result = Regex.Replace(test, pattern, m =>
            m.Groups["start"].Value +
            HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups["content"].Value)) +
            m.Groups["end"].Value);
var doc = XElement.Parse(result);
like image 137
Ahmad Mageed Avatar answered Oct 09 '22 09:10

Ahmad Mageed


Your string doesn't contain valid XML, that's the issue. You need to change your string to:

<MyXML><SubXML><XmlEntry Element="test" value="wow&amp;" /></SubXML></MyXML>"
like image 21
Justin Niessner Avatar answered Oct 09 '22 08:10

Justin Niessner