Adding new elements to XmlDocument that abide by XSD - c#

Currently, I'm adding elements to my XmlDocument using XPath notation for which I've written code to that places the element at the proper location in the file. With one exception. I don't know how to make it pay attention to the sequence rules defined in my XSD file.
Is there a way to add an element to an XmlDocument so that is abides by the sequence define in the XSD that governs my XML file?
For example, my xml document should look like:
<rootTag>
<area name="I define an area">
<description>some text here</description>
<point x="1" y="1" />
<point x="2" y="2" />
<point x="3" y="3" />
</area>
</rootTag>
Yet I get, depending on the order in which the user enters values for the child tags above:
<rootTag>
<area name="I define an area">
<point x="1" y="1" />
<point x="2" y="2" />
<point x="3" y="3" />
<description>some text here</description>
</area>
</rootTag>
To correct the above, I create a DataSet (named tempXmlDataset) from the XSD file. I pass the contents of the XmlDocument into tempXmlDataset and things get re-ordered appropriately.
However, my problem is caused by an option for the first child of the XML document. This option is defined in the XSD to allow for "area", "line" or "point" objects. "area" and "line" both have "point" elements as children. But child "point" is not the same as "point" object. So, as you might already realize, tempXmlDataset.ReadXmlSchema(...) creates a "point" table which only has x and y in it. This is by definition of the children for "area" and "line".
So when my code runs tempXmlDataset.ReadXml(...) the attributes for "point" object do not get read in because it sees "point" object as child "point". Here's an example of "point" object:
<rootTag>
<point name="I define a point" x="3" y="3" otherAttributes="">
<description>some text here</description>
</point>
</rootTag>

Since you tagged this C#, I assume you're on the .NET platform. The System.Xml.Schema would be your best friend. For a program that uses the above API to generate XML, that also comes with source code you could use to understand how to solve your issue, I would use the XmlSampleGenerator.
Generating a sample XML requires exactly what you need in terms of constraining the XPath the user may enter at a given point in time. I believe you will have to constrain the XPath you allow based on where you are in the editing process, right from the beginning, otherwise, one single mistake could make the whole approach useless.
If you don't constrain from the beginning, it might be impossible to try to re-order based on an XSD (please read this also in SO)...

use xsd.exe to generate the required code based on the xsd for classes. Don't try to create the dataset for this case. You can then use the generated code together with the XmlSerializer to produce the needed xml files.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
Also see:
http://msdn.microsoft.com/en-us/library/ms950721.aspx

Related

C# API for XML structure comparison

is there a way to programmatically compare structures of 2 XML files, but not their values?
More concretely, if you have 2 xml files:
<car>
<numberofwheels>4</numberofwheels>
<carcolor color="red" dateofpainting="2015-10-10" />
</car>
and
<car>
<numberofwheels>7</numberofwheels>
<carcolor color="blue" />
</car>
it would only notice that attribute dateofpainting is missing, but not the change of values (numberofwheels and color). I also don't care about blanks, newlines, attribute order, etc...
There is an XML Diff and Patch Tool from Microsoft, but as far as I can see, it also checks xml values and you cannot set it up to ignore them.
If any one of the structure is predefined,then you can use the XML schema do find the mismatch. If not then you have to traverse the document node by node using XMLDocument/XMLReader class and you can get the difference list.

Converting an XML file to a multi-dimensional dictionnary

I'm trying to import XML files into my C# code.
I would like to access these data like a dictionnary element.
Example:
// XML:
<root>
<node>
<value1>
</value1>
<value2>
<properties>
</properties>
</value2>
<randomnode>
<blabla>X</blabla>
</randomnode>
</node>
</root>
// C#:
values["root"]["node"]["randomnode"]["blabla"] == "X" // true
Is there any way to do this?
As far as I've searched, I could only get a dictionnary using XElements, but it was only 2-dimensions and I had to specify names and values as attributes in the XML file.
Thanks for answering!
I suggest you to use dynamic type for this. See here for code. Or here.
I've used sharpSerializer for that. Heres a pretty good walkthrough:
XML Serialization of Generic Dictionary, Multidimensional Array, and Inherited Type, with sharpSerializer .NET

XML Parsing - Removing nodes and keeping the overall structure

so I have a massive XML file that contains a structure similar to this one:
<Item ItemId=";ResTVersion" ItemType="0" PsrId="245" Leaf="false">
<Disp Icon="Str" Expand="true" Disp="true" LocTbl="false" Order="13352" />
<Modified By="sachink" DateTime="2008-12-16T19:02:35Z" />
<PsrProps>
<Str Name="Kii" Val="yyyyyyyyyyyyy" />
</PsrProps>
<Item ItemId=";ResTFileVersion" ItemType="0;ResT" PsrId="245" InstFlg="true" Leaf="true">
<Str Cat="Text" UsrLk="true">
<Val><![CDATA[ttttttttt]]></Val>
<Tgt Cat="Text" Orig="New">
<Val><![CDATA[ttttttttt]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" Order="13353" />
<Modified By="sachink" DateTime="2008-12-16T19:02:35Z" />
<Cmts>
<Cmt Name="Dev"><![CDATA[{Locked}]]></Cmt>
</Cmts>
</Item>
<Item ItemId=";ResTLanguageTag" ItemType="0;ResT" PsrId="245" InstFlg="true" Leaf="true">
<Str Cat="Text" UsrLk="true">
<Val><![CDATA[en-US]]></Val>
<Tgt Cat="Text" Orig="New">
<Val><![CDATA[en-US]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" Order="13354" />
<Modified By="sachink" DateTime="2008-12-16T19:02:35Z" />
<Cmts>
<Cmt Name="Dev"><![CDATA[=.ABVUDHUIDSHFUIDSHFUISHDFUIDSH iusdhfUIHAs]]></Cmt>
</Cmts>
</Item>
</Item>
I have several item ids and I want to create a new xml that respects the old structure.
I use this code to retrieve the nodes that I want, and then create the new XML.
XmlNodeList nodes = originalXML.SelectNodes("//*[contains(#ItemId,'" + id + "')]");
So what I want is to remove some nodes but I only have the ids of the ones I want to keep.
The problem is how do you keep the outer structure of an xml, when you use the selectnodes function, to get the inner nodes?
Thanks!
I would go the opposite way: remove what you don't need. It's hard to build an XmlDocument from scratch (takes a lot of coding).
I think you will be better off removing the nodes you don't want from the structure you already have.
XmlNodeList nodes = originalXML.SelectNodes("/*[not(contains(#test,'test'))]")
foreach(XmlNode node in nodes)
originalXML.RemoveChild(node);
should work.
If you need to preserve your original structure you can originalXML.Clone() it.
Sidenote: You might want to look into System.Xml.Linq.XDocument and System.Xml.Linq.XElement I find those a lot easier to use.

How can I deserialize this XML to a useful data structure?

I am working with a receipt format that is returned to me as a "saml assertion". This is a known and well defined format, but on my current platform, I don't have access to libraries that can deserialize the xml to the original classes.
I've determined that I will likely need to roll my own classes but given the format of the xml, I don't really know what the C# classes would look like or the definition and tricks needed to get it to deserialize.
The goal is that from the receipt, create a list of C# objects that I can examine. I would like to retain the value in Format, in the Name node as well as the id. In addition, part of what makes this challenging is that Statement consists of both subject and attribute elements. One of the questions I would like to ask the list is, does the list contain a Assertion that has an Attribute node with "Gamma" having the value of 999.
here's the format:
<Assertion>
<Statement>
<Subject>
<Name Format="http://name.com/123/45/ProductName" Id="123">123456</Name>
</Subject>
<Attribute Name="Alpha">
<Value>111</Value>
</Attribute>
<Attribute Name="Gamma">
<Value>22</Value>
</Attribute>
...
<Attribute Name="Delta">
<Value>3</Value>
</Attribute>
</Statement>
</Assertion>
You can use the XML Schema Definition Tool (Xsd.exe) to get your class structure started.
Here's an excellent blog post by Yogesh Joshi that walks through the whole process: http://blogs.msdn.com/b/yojoshi/archive/2011/05/14/xml-serialization-and-deserialization-entity-classes-with-xsd-exe.aspx
As Kon said in the comment, the Attribute nodes should be wrapped in a container element. I haven't found any good way to deserialize a list that also has other elements in it (or attributes, either). You'll probably be forced to have your class implement IXmlSerializable and write more than you would otherwise need to.

How to embed xml in xml

I need to embed an entire well-formed xml document within another xml document. However, I would rather avoid CDATA (personal distaste) and also I would like to avoid the parser that will receive the whole document from wasting time parsing the embedded xml. The embedded xml could be quite significant, and I would like the code that will receive the whole file to treat the embedded xml as arbitrary data.
The idea that immediately came to mind is to encode the embedded xml in base64, or to zip it. Does this sound ok?
I'm coding in C# by the way.
You could convert the XML to a byte array, then convert it to binary64 format. That will allow you to nest it in an element, and not have to use CDATA.
The W3C-approved way of doing this is XInclude. There is an implementation for .Net at http://mvp-xml.sourceforge.net/xinclude/
Just a quick note, I have gone the base64 route and it works just fine but it does come with a stiff performance penalty, especially under heavy usage. We do this with document fragments upto 20MB and after base64 encoding they can take upwards of 65MB (with tags and data), even with zipping.
However, the bigger issue is that .NET base64 encoding can consume up-to 10x the memory when performing the encoding/decoding and can frequently cause OOM exceptions if done repeatedly and/or done on multiple threads.
Someone, on a similar question recommended ProtoBuf as an option, as well as Fast InfoSet as another option.
Depending on how you construct the XML, one way is to not care about it and let the framework handle it.
XmlDocument doc = new XmlDocument();
doc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><helloworld></helloworld>");
string xml = "<how><are><you reply=\"i am fine\">really</you></are></how>";
doc.GetElementsByTagName("helloworld")[0].InnerText = xml;
The output will be something like a HTMLEncoded string:
<?xml version="1.0" encoding="utf-8"?>
<helloworld><how><are><you
reply="i am fine">really</you></are></how>
</helloworld>
I would encode it in your favorite way (e.g. base64 or HttpServerUtility::UrlEncode, ...) and then embed it.
If you don't need the xml declaration (first line of the document), just insert the root element (with all childs) into the tree of the other xml document as a child of an existing element. Use a different namespace to seperate the inserted elements.
It seems that serialization is the recommended method.
Can't you use XSLT for this? Perhaps using xsl:copy or xsl:copy-of? This is what XSLT is for.
I use Comments for this :
<!-- your xml text -->
[EDITED]
If the embedded xml with comments, replace it with a different syntax.
<?xml version="1.0" encoding="iso-8859-1" ?>
<xml>
<status code="0" msg="" cause="" />
<data>
<order type="07" user="none" attrib="..." >
<xmlembeded >
<!--
<?xml version="1.0" encoding="iso-8859-1" ?>
<xml>
<status ret="000 "/>
<data>
<allxml_here />
<!** embedeb comments **>
</data>
<xml>
-->
</xmlembeded >
</order>
<context sessionid="12345678" scriptname="/from/..." attrib="..." />
</data>
</xml>

Categories

Resources