Converting an XML document to fluent C# - c#

I'd like to convert an external XML document without any XSD schema associated with it into a fluent .NET object.
I have a simple XML file like:
<application>
<parameters>
<param></param>
<param></param>
</parameters>
<generation />
<entities>
<entity ID="1">
<PropTest>Test</PropTest>
</entity>
<entity ID="2">
<PropTest>Another Test</PropTest>
</entity>
</entities>
</application>
I'd like to navigate the document like:
var xConfig = new XmlConfig("file.xml");
// testValue should be assigned "Test"
string testValue = xConfig.Generation.Entities.Entity(1).PropTest;
What is the best way to achieve this in .NET 3.5?

Arguably, the best way to do this these days is with Linq to XML. It is a whole lot easier than messing with XSDs and convoluted class definitions.
XDocument doc = XDocument.Load("file.xml");
var val = doc
.Descendants("entity")
.Where(p => p.Attribute("ID").Value == "1")
.Descendants("PropTest")
.FirstOrDefault();
if (val != null)
Console.WriteLine(val.Value);
The sample file.xml that I used was:
<?xml version="1.0" encoding="utf-8" ?>
<application>
<parameters>
<param></param>
<param></param>
</parameters>
<generation>
<entities>
<entity ID="1">
<PropTest>Test</PropTest>
</entity>
<entity ID="2">Another Test</entity>
</entities>
</generation>
</application>

I just noticed that Lusid also wrote about Linq to SQL while I was writing my answer, but he used XDocument.
Here is my version (file.xml is the XML given in the question):
string testValue =
(string) XElement.Load("file.xml")
.Element("entities")
.Elements("entity")
.FirstOrDefault(entity => entity.Attribute("ID")
.Value == "1") ?? string.Empty;

I would look at xsd.exe. You can also go here for a more informative tutorial on how to use it.
Basically you will be create .NET class equivalents of your XSD. You will then be able to serialize and deserialize your XML and objects.

Kevin Hazzard has written a fluent XML interface for C# using the .NET 4.0 dynamic type part 1 and part 2. This would allow code like:
var v = dx.application.entities.entity[0].PropTest.Value;

If you just extract the schema(which should be easy with xsd.exe) then this online tool (which can also be downloaded) could help you, I tried it and it's ok.

Define classes derived from ConfigurationSection/ConfigurationElement etc. They map to xml files nicely (that's what they'r built for) See MSDN for this. Another way is to create POCO objects and set XML serialization attributes over properties then use System.XML.XMLSerializer to serialize/deserialize to/from XML. See MSDN for XML Serialization.

Related

adding attributes to elements

I am seralising a C# class into an xml, all good except the namespace attributes are not getting inserted into the xml file.
tried the following above the Document as well as the Documents property:
[XmlAttribute("xmlns:xsi",Namespace ="www.test.com")]
[XmlAttribute("xsi:type",Namespace ="somename")]
but that didn’t work :(
The xml I want to appear in the xml file is:
<someOtherElement></someOtherElement>
<someOtherElement></someOtherElement>
<Documents>
<Document xmlns:xsi="www.test.com" xsi:type=“somename”>
<Name></Name>
<DOB></DOB>
</Document>
</Documents>
<someOtherElement></someOtherElement>
<someOtherElement></someOtherElement>
Would love any feedback. Thanks!
The following worked for the "somename" attribute:
[xmlAttribute(Namespace =
System.Xml.Schema.XmlSchema.InstanceNamespace)]
public string someAttr {get;set} = "somename"
however still figuring out the xmlns:xsi attribute

Adding XElement to XDocument with same namespace

I have a XDocument with the following structure where I want to add a bunch of XElements.
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr>
...
</GrpHdr>
<!-- loaded nodes go here -->
<CstmrCdtTrfInitn>
</Document>
The XElements have the following structure:
<PmtInf xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
...
</PmtInf>
The problem is that the namespace in child nodes is not supported at the recipients side and since it is the same as the XDocument's namespace - it is redundant. How do I avoid/remove that namespace on the child nodes?
The code that I use right now:
var childNodes = new XElement(NameSpace + "GrpHdr", ...);
XElement[] loadedNodes = ...;//Loads from a service using XElement.Load
var content = new XElement(NameSpace + "CstmrCdtTrfInitn", childNodes,loadedNodes));
When calling Save on XElement or XDocument, there is a flags enum SaveOptions that allow you to control to some extent how the document is written to XML.
The easiest way to achieve what you want (without traversing the structure to remove the redundant attributes) is to use one of these flags: OmitDuplicateNamespaces.
Remove the duplicate namespace declarations while serializing.
You can see in this fiddle that adding this flag changes my example output from this:
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr />
<PmtInf xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">...</PmtInf>
</CstmrCdtTrfInitn>
</Document>
To this:
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr />
<PmtInf>...</PmtInf>
</CstmrCdtTrfInitn>
</Document>

How do I get multiple namespaces in XML C#?

Following is the XML format:
<?xml version="1.0" encoding="UTF-8"?>
<package version="2.0" unique-identifier="isbn0000000000000" xmlns="http://www.idpf.org/2007/opf">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>Eltern Family</dc:title>
<dc:creator></dc:creator>
<dc:publisher></dc:publisher>
<dc:rights></dc:rights>
<dc:identifier id="isbn0000000000000">0000000000000</dc:identifier>
<dc:language>de</dc:language>
<dc:date opf:event="publication">2019-02-11</dc:date>
</metadata>
</package>
Here I got the default Namespace by XDocument.Root.GetDefaultNamespace();. But as you can see, there are multiple namespaces in the <metadata> XML node. The problem is that, they are variable i.e., each XML may have different values, so I cannot declare a variable with one fixed value.
How do I get the namespaces, so that I can add values to the descendant elements?
Please help.
Regards
Aman
If, as you say, you want to set the content of dc:rights, then you need to get hold of that element.
You can do this by name - the 'qualified name' is made of of the namespace and a local name. The namespace prefix dc is not actually important in and of itself, it's just used as a shorthand to refer to the namespace within the document.
Assuming you have parsed this XML to an XDocument called doc:
XNamespace dc = "http://purl.org/dc/elements/1.1/"
var rights = doc.Descendants(dc + "rights").Single();
rights.Value = "text";

Setting XML Attribute for Sandcastle files

I have a Sandcastle project that handles some documentation for me. I do some of the process in code to build up the files.
Nonetheless I want to create a link that will navigate to another page.
C# Code
XmlElement link = document.CreateElement("link");
link.SetAttribute("xlink:href", mapGuid.ToString());
This will create the element and then set the attribute. The outcome looks like this:
<link href="10e3ca23-4b79-42f3-b89c-e6fe924ceef3" xmlns="" />
but it should look like this
<link xlink:href="10e3ca23-4b79-42f3-b89c-e6fe924ceef3" xmlns="" />
The first link does not work but when I add xlink: in front of href then it works.
My question is how can I fix this?
Thanks in advance
I normally use XML Linq and get namesapce out of parent like this
XElement link = new XElement("link");
XNamespace ns = link.Name.Namespace;
link.Add(new XAttribute(ns + "href", "10e3ca23-4b79-42f3-b89c-e6fe924ceef3"));

How to do simple XML schema validation with no namespaces in C#

I have generated a set of classes using xsd.exe and created an XML document from the resulting generated code. I would now like to validate the serialized class instance against the original xsd.
My XML is like this:
<?xml version="1.0" encoding="UTF-8"?>
<MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-- rest of XML document here
</MyRoot>
My XSD is like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MyRoot" type="MyRootType"/>
-- MyRootType definition and rest of XSD
</xs:schema>
When I try to validate the XML using a XmlReader, I get the following error:
"The 'MyRoot' element is not declared."
What could be wrong?
In your MyRoot element, you need to add the location of the XSD. I would also recommend defining the namespace (unless you have good reason not to).
<api:MyRoot xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:api='http://www.myserver.com/schema'
xsi:schemaLocation='http://www.myserver.com/schema http://www.myserver.com/schema/websuiterecord.xsd'>
</api:MyRoot>
This way, the validation tool knows where to find your XSD to validate your XML against.
The approach was correct, but the XSD was not infact being read. I corrected this and it worked as expected.

Categories

Resources