UPDATE: Added more detail per request
I am trying to create an xml configuration file for my application. The file contains a list of criteria to search and replace in an html document. The problem is, I need to search for character strings like  . I do not want my code to read the decoded item, but the text itself.
Admitting to being very new to XML, I did make some attempts at meeting the requirements. I read a load of links here on Stackoverflow regarding CDATA and ATTRIBUTES and so on, but the examples here (and elsewhere) seem to focus on creating one single line in an xml file, not multiple.
Here is one of many attempts I have made to no avail:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE item [
<!ELEMENT item (id, replacewith)>
<!ELEMENT id (#CDATA)>
<!ELEMENT replacewith (#CDATA)>
]>
]>
<item id=" " replacewith=" ">Non breaking space</item>
<item id="‑" replacewith="-">Non breaking hyphen</item>
This document gives me a number of errors, including:
In the DOCTYPE, I get errors like <!ELEMENT id (#CDATA)>. In the CDATA area, Visual Studio informs me it is expecting a ',' or '|'.
]> gives me an error of invalid token at the root of the document.
And of course, after the second <item entry, I get an error stating XML document cannot contain multiple root level elements.
How can I write an xml file that includes multiple items and allows me to store and retrieve the text within the element, rather than the interpreted characters?
If it helps any, I am using .Net, C#, and Visual Studio.
EDIT:
The purpose of this xml file is to provide my code with a list of things to search and replace in an html file. The xml file simply contains a list of what to search for and what to replace with.
Here is the file I have in place right now:
<?xml version="1.0" encoding="utf-8" ?>
<Items>
<item id="‑" replacewith="-">Non breaking hyphen</item>
<item id=" " replacewith=" ">Non breaking hyphen</item>
</Items>
Using the first as an example, I want to read the text ‑ but instead when I read this, I get - because that is what the code represents.
Any help or pointers you can give would be helpful.
To elaborate on my comment: XML acts like HTML due to the reserved characters. An ampersand prefixes keywords or character codes to translate into a literal string when read in with any type of parser (browser, XML reader, etc).
The easiest way to escape the values to make sure they are read back in as the literal that you want is to put them in as if you were encoding it for web. For example, to create your XML document, I did this:
XmlDocument xmlDoc = new XmlDocument();
XmlElement xmlItem;
XmlAttribute xmlAttr;
XmlText xmlText;
// Declaration
XmlDeclaration xmlDec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement xmlRoot = xmlDoc.DocumentElement;
xmlDoc.InsertBefore(xmlDec, xmlRoot);
// Items
XmlElement xmlItems = xmlDoc.CreateElement(string.Empty, "Items", string.Empty);
xmlDoc.AppendChild(xmlItems);
// Item #1
xmlItem = xmlDoc.CreateElement(string.Empty, "item", string.Empty);
xmlAttr = xmlDoc.CreateAttribute(string.Empty, "id", string.Empty);
xmlAttr.Value = "‑";
xmlItem.Attributes.Append(xmlAttr);
xmlAttr = xmlDoc.CreateAttribute(string.Empty, "replacewith", string.Empty);
xmlAttr.Value = "-";
xmlItem.Attributes.Append(xmlAttr);
xmlText = xmlDoc.CreateTextNode("Non breaking hyphen");
xmlItem.AppendChild(xmlText);
xmlItems.AppendChild(xmlItem);
// Item #2
xmlItem = xmlDoc.CreateElement(string.Empty, "item", string.Empty);
xmlAttr = xmlDoc.CreateAttribute(string.Empty, "id", string.Empty);
xmlAttr.Value = " ";
xmlItem.Attributes.Append(xmlAttr);
xmlAttr = xmlDoc.CreateAttribute(string.Empty, "replacewith", string.Empty);
xmlAttr.Value = " ";
xmlItem.Attributes.Append(xmlAttr);
xmlText = xmlDoc.CreateTextNode("Non breaking hyphen");
xmlItem.AppendChild(xmlText);
xmlItems.AppendChild(xmlItem);
// For formatting
StringBuilder xmlBuilder = new StringBuilder();
XmlWriterSettings xmlSettings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = "\r\n",
NewLineHandling = NewLineHandling.Replace
};
using (XmlWriter writer = XmlWriter.Create(xmlBuilder, xmlSettings))
{
xmlDoc.Save(writer);
}
xmlOutput.Text = xmlBuilder.ToString();
Notice that I put in your id values with what you are expecting. Now, look at how it gets encoded:
<?xml version="1.0" encoding="utf-16"?>
<Items>
<item id="‑" replacewith="-">Non breaking hyphen</item>
<item id=" " replacewith=" ">Non breaking hyphen</item>
</Items>
The only difference between yours and this one is that the ampersand was encoded as & and the rest remained as a string literal. This is normal behavior for XML. When you read it back in, it will come back as the literal ‑ and .
I am trying to store XPath of an XML attribute as a string in a separate file so that if XPath changes, I can easily modify the navigation to the attribute without changing code.
For example, in following XML:
<Result>
<Server = "main">
<Client id="1"></Client>
</Server>
</Result>
if I want to navigate to id attribute of Client element, I can have following string:
Result->Server->Client->id
I am not sure how in C# I can navigate using this string form of XPath and then, read the attribute value from the target XML.
Please help.
Harit
Well, firstly, your XML is a bit strange, with
<Server = "main">
Do you mean
<Server id="main">
But, regardless of that, you could just store the XPath directly instead of your string version. Like:
/Result/Server/Client[0]/#id
then you read the string from the file and pass it into something like:
public string GetClientIdString(string xPathString)
{
var doc = new XmlDocument();
doc.Load("SomeXml.xml");
return doc.DocumentElement.SelectSingleNode(xPathString).Value;
}
The issue becomes that you can't really store the XPath exactly how you would like if you plan on having more than one Client under Server. If you need that functionality, though, you could parse out your version of the XPath and do something like:
public IEnumerable<string> GetClientIdStrings(string elementXPath, string attribute)
{
var doc = new XmlDocument();
doc.Load(SomeXml.xml);
var clientIdStrings = new List<string>();
foreach(var node in doc.DocumentElement.SelectNodes(elementXPath))
{
clientIdStrings.Add(node.Attributes[attribute].Value);
}
return clientIdStrings;
}
I'm trying to consume an Axis2 REST XML response using C#.NET with RestSharp and Linq. However I can't seem to serialize the XML response either using RestSharp or manually.
This is an example of the XML response from Axis2:
<ns:response xmlns:ns="http://com.some.where" xmlns:ax2488="http://com.some.where/xsd">
<ns:return xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax2488:Book">
<ax2488:field1>Orson Scott Card</ax2488:field1>
<ax2488:field1>Some One Else</ax2488:field1>
<ax2488:field2>1</ax2488:field2>
<ax2488:isbn10>142996393X</ax2488:isbn10>
<ax2488:isbn13>9781429963930</ax2488:isbn13>
<ax2488:date>2010</ax2488:date>
<ax2488:blah>Tom Doherty Associates</ax2488:blah>
<ax2488:ssss>on loan</ax2488:ssss>
<ax2488:name>Ender's Game Volume 1 of The Ender Quintet</ax2488:name>
</ns:return>
When I try to get the elements out there using XElements (Linq), I always get null?
var elements = root.Elements("Book");
I've tried a few different element names with no luck.
Also, using RestSharp, it successfully gets the first and only response, however if I have multiple responses, it returns null.
var response1 = _client.Execute<Book>(request);
var response2 = _client.Execute<List<Book>>(request);
Any help appreciated.
One possible way, using XDocument with XPath query :
using System.Xml.XPath;
var nsmgr = new XmlNamespaceManager(new NameTable());
//register prefixes for use in XPath
nsmgr.AddNamespace("ns", "http://com.some.where");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
var xpath = "//ns:response/ns:return[#xsi:type='ax2488:Book']";
//above xpath consists of path from root to <ns:return> : //ns:response/ns:return
//and criteria for <ns:return> : [#xsi:type='ax2488:Book']
var doc = XDocument.Load("path_to_xml_file.xml");
var returnElements = doc.XPathSelectElements(xpath, nsmgr);
I assumed that your XML structure looks about like this :
<root>
<ns:response xmlns:ns="http://com.some.where" xmlns:ax2488="http://com.some.where/xsd">
<ns:return xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax2488:Book">
<ax2488:field1>Orson Scott Card</ax2488:field1>
<ax2488:field1>Some One Else</ax2488:field1>
<ax2488:field2>1</ax2488:field2>
<ax2488:isbn10>142996393X</ax2488:isbn10>
<ax2488:isbn13>9781429963930</ax2488:isbn13>
<ax2488:date>2010</ax2488:date>
<ax2488:blah>Tom Doherty Associates</ax2488:blah>
<ax2488:ssss>on loan</ax2488:ssss>
<ax2488:name>Ender's Game Volume 1 of The Ender Quintet</ax2488:name>
</ns:return>
</ns:response>
<ns:response xmlns:ns="http://com.some.where" xmlns:ax2488="http://com.some.where/xsd">
........
</ns:response>
........
........
</root>
I'm getting a JsonSerializationException calling DeserializeXmlNode() on JSON data that starts with [[ (i.e. it's an array of arrays).
What is the best
way to turn this into XML?
Are there any other JSON schemas that can't be turned into XML?
Update: How the XML should appear is an interesting question. Having an array of arrays means there is no root node (that's an easy one - insert ) but also the set of children nodes have no name. I'm not sure what makes sense here. And this may be a deal killer for using XPath on JSON. So on this part too, any suggestions?
Update 2 - the JSON data:
[["P0010001","NAME","state"],
["4779736","Alabama","01"],
["710231","Alaska","02"],
["6392017","Arizona","04"],
["2915918","Arkansas","05"],
["37253956","California","06"],
["5029196","Colorado","08"],
["3574097","Connecticut","09"],
["897934","Delaware","10"],
["601723","District of Columbia","11"],
["18801310","Florida","12"],
["9687653","Georgia","13"],
["1360301","Hawaii","15"],
["1567582","Idaho","16"],
["12830632","Illinois","17"],
["6483802","Indiana","18"],
["3046355","Iowa","19"],
["2853118","Kansas","20"],
["4339367","Kentucky","21"],
["4533372","Louisiana","22"],
["1328361","Maine","23"],
["5773552","Maryland","24"],
["6547629","Massachusetts","25"],
["9883640","Michigan","26"],
["5303925","Minnesota","27"],
["2967297","Mississippi","28"],
["5988927","Missouri","29"],
["989415","Montana","30"],
["1826341","Nebraska","31"],
["2700551","Nevada","32"],
["1316470","New Hampshire","33"],
["8791894","New Jersey","34"],
["2059179","New Mexico","35"],
["19378102","New York","36"],
["9535483","North Carolina","37"],
["672591","North Dakota","38"],
["11536504","Ohio","39"],
["3751351","Oklahoma","40"],
["3831074","Oregon","41"],
["12702379","Pennsylvania","42"],
["1052567","Rhode Island","44"],
["4625364","South Carolina","45"],
["814180","South Dakota","46"],
["6346105","Tennessee","47"],
["25145561","Texas","48"],
["2763885","Utah","49"],
["625741","Vermont","50"],
["8001024","Virginia","51"],
["6724540","Washington","53"],
["1852994","West Virginia","54"],
["5686986","Wisconsin","55"],
["563626","Wyoming","56"],
["3725789","Puerto Rico","72"]]
I had an array of objects, shaped like:
[{foo:bar}, {foo:bar2}]
...What I did to work around this problem is to wrap the text first like so:
public XmlDocument JsonArrayToXml(string json)
{
var wrappedDocument = string.Format("{{ item: {0} }}", json);
var xDocument = JsonConvert.DeserializeXmlNode(wrappedDocument, "collection");
return xDocument;
}
This does not throw an error. The shape of the XML resembles:
<?xml version="1.0" encoding="UTF-8"?>
<collection>
<item>
<foo>bar</foo>
</item>
<item>
<foo>bar2</foo>
</item>
</collection>