XElement namespaces (How to?) - c#

How to create xml document with node prefix like:
<sphinx:docset>
<sphinx:schema>
<sphinx:field name="subject"/>
<sphinx:field name="content"/>
<sphinx:attr name="published" type="timestamp"/>
</sphinx:schema>
When I try to run something like new XElement("sphinx:docset") i getting exception
Unhandled Exception: System.Xml.XmlException: The ':' character, hexadecimal val
ue 0x3A, cannot be included in a name.
at System.Xml.XmlConvert.VerifyNCName(String name, ExceptionType exceptionTyp
e)
at System.Xml.Linq.XName..ctor(XNamespace ns, String localName)
at System.Xml.Linq.XNamespace.GetName(String localName)
at System.Xml.Linq.XName.Get(String expandedName)

It's really easy in LINQ to XML:
XNamespace ns = "sphinx";
XElement element = new XElement(ns + "docset");
Or to make the "alias" work properly to make it look like your examples, something like this:
XNamespace ns = "http://url/for/sphinx";
XElement element = new XElement("container",
new XAttribute(XNamespace.Xmlns + "sphinx", ns),
new XElement(ns + "docset",
new XElement(ns + "schema"),
new XElement(ns + "field", new XAttribute("name", "subject")),
new XElement(ns + "field", new XAttribute("name", "content")),
new XElement(ns + "attr",
new XAttribute("name", "published"),
new XAttribute("type", "timestamp"))));
That produces:
<container xmlns:sphinx="http://url/for/sphinx">
<sphinx:docset>
<sphinx:schema />
<sphinx:field name="subject" />
<sphinx:field name="content" />
<sphinx:attr name="published" type="timestamp" />
</sphinx:docset>
</container>

You can read the namespace of your document and use it in queries like this:
XDocument xml = XDocument.Load(address);
XNamespace ns = xml.Root.Name.Namespace;
foreach (XElement el in xml.Descendants(ns + "whateverYourElementNameIs"))
//do stuff

Related

C# XElement how do I add different attributes in a specific order?

I have the following C# code to generate an XML document. The problem is that I need to swap the order of the attributes in the tag "CState". Therefore I have already tried several things. Unfortunately it does not work or I get an exception.
XNamespace ns = "http:dev.test.com/Job/Con";
XNamespace nsi = "http:www.w3.org/2001/XMLSchema-instance";
XElement doc = new XElement(ns + "CState", new XAttribute(XNamespace.Xmlns + "xsi", nsi),
new XElement(ns + "Page",
new XElement(ns + "Field", new XAttribute("dName", "MembershipNumber"), new XAttribute("type", "Text"), new XAttribute("value", "123456")),
new XElement(ns + "Field", new XAttribute("dName", "FirstName"), new XAttribute("type", "Text"), new XAttribute("value", "Michael")),
new XElement(ns + "Field", new XAttribute("dName", "LastName"), new XAttribute("type", "Text"), new XAttribute("value", "Hendly"))
));
This is the output in the XML file.
<?xml version="1.0" encoding="utf-8"?>
<CState xmlns:xsi="http:www.w3.org/2001/XMLSchema-instance" xmlns="http:dev.test.com/Job/Con">
<Page>
<Field dName="MembershipNumber" type="Text" value="123456" />
<Field dName="FirstName" type="Text" value="Michael" />
<Field dName="LastName" type="Text" value="Hendly" />
</Page>
</ControlStatements>
However, the attributes should appear in a different order.
This is how the second line in the XML file is created (incorrect):
<CState xmlns:xsi="http:www.w3.org/2001/XMLSchema-instance" xmlns="http:dev.test.com/Job/Con">
This is how the second line should be created in the XML file (correct):
<CState xmlns="http:dev.test.com/Job/Con" xmlns:xsi="http:www.w3.org/2001/XMLSchema-instance">
How can I achieve this as easily as possible?

How to specify an xmlns for XDocument?

I tried:
textBox1.Text = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new XElement("root1", new XAttribute( "xmlns", #"http://example.com"), new XElement("a", "b"))
).ToString();
But I get:
The prefix '' cannot be redefined from '' to 'http://example.com' within the same start element tag.
I also tried substituting (according to an answer I found) :
XAttribute(XNamespace.Xmlns,...
But got an error as well.
Note: I'm not trying to have more than one xmlns in the document.
The way the XDocument API works with namespace-scoped names is as XName instances. These are fairly easy to work with, as long as you accept that an XML name isn't just a string, but a scoped identifier. Here's how I do it:
var ns = XNamespace.Get("http://example.com");
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null));
var root = new XElement(ns + "root1", new XElement(ns + "a", "b"));
doc.Add(root);
Result:
<root1 xmlns="http://example.com">
<a>b</a>
</root1>
Note the + operator is overloaded to accept an XNamespace and a String to result in and XName instance.

Linq to XML, C#

I have an xml in XDocument object (LINQ to XML). I need to add the namespace to each Xelement/node in the Xdocument.
I dont want to add in the below way. beceause i already have the xml in xdoc.
XDocument xDoc = new XDocument(
new XElement(ns + "root",
new XElement(ns + "person",
new XAttribute("id", 1),
new XElement(ns + "firstname", "jack"),
Below is the format i have
<root>
<person>1</person>
<firstname>jack</firstname>
</root>
I want to convert it to this below format
<emp:root>
<emp:person>1</emp:person>
<emp:firstname>jack</emp:firstname>
</emp:root>
foreach (var node in xDoc.Descendants())
{
node.Name = ns + node.Name.LocalName;
}
That should work:
Side note the namespace will only appear on the root node.

Create XML doc by LINQ, add xmlns,xmlns:xsi to it

I try to create an GPX XML document by LINQ to XML.
Everything works great, except adding xmlns, xmlns:xsi attributes to the doc. By trying it different way I get different exceptions.
My code:
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "no"),
new XElement("gpx",
new XAttribute("creator", "XML tester"),
new XAttribute("version","1.1"),
new XElement("wpt",
new XAttribute("lat","7.0"),
new XAttribute("lon","19.0"),
new XElement("name","test"),
new XElement("sym","Car"))
));
The output should also contain this:
xmlns="http://www.topografix.com/GPX/1/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
How can I add it by Linq to XML? I tried several ways but it does not work, exceptions during compile time.
See How to: Control Namespace Prefixes. You could use code like this:
XNamespace ns = "http://www.topografix.com/GPX/1/1";
XNamespace xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "no"),
new XElement(ns + "gpx",
new XAttribute(XNamespace.Xmlns + "xsi", xsiNs),
new XAttribute(xsiNs + "schemaLocation",
"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"),
new XAttribute("creator", "XML tester"),
new XAttribute("version","1.1"),
new XElement(ns + "wpt",
new XAttribute("lat","7.0"),
new XAttribute("lon","19.0"),
new XElement(ns + "name","test"),
new XElement(ns + "sym","Car"))
));
You have to specify the namespace for each element, because that's what using xmlns this way means.
From http://www.falconwebtech.com/post/2010/06/03/Adding-schemaLocation-attribute-to-XElement-in-LINQ-to-XML.aspx:
To generate the following root node and namespaces:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://www.foo.bar someSchema.xsd"
xmlns="http://www.foo.bar" >
</root>
Use the following code:
XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
XNamespace defaultNamespace = XNamespace.Get("http://www.foo.bar");
XElement doc = new XElement(
new XElement(defaultNamespace + "root",
new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
new XAttribute(xsi + "schemaLocation", "http://www.foo.bar someSchema.xsd")
)
);
Be aware - if you want to add elements to the document, you need to specify the defaultNamespace in the element name or you will get xmlns="" added to your element. For example, to add a child element "count" to the above document, use:
xdoc.Add(new XElement(defaultNamespace + "count", 0)

How do I add multiple Namespace declarations to an XDocument?

I'm using an XDocument to build an Xml document in a known structure. The structure I am trying to build is as follows:
<request xmlns:ns4="http://www.example.com/a" xmlns:ns3="http://www.example.com/b" xmlns:ns2="http://www.example.com/c" >
<requestId>d78d4056-a831-4c7d-a357-d14402f623fc</requestId>
....
</request>
Notice the "xmlns:nsX" attributes.
I am trying, without success, to add these attributes to my "request" element.
XNamespace ns4 = XNamespace.Get("http://www.example.com/a");
XNamespace ns3 = XNamespace.Get("http://www.example.com/b");
XNamespace ns2 = XNamespace.Get("http://www.example.com/c");
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "no"),
new XElement("request",
new XAttribute("ns4", ns4),
new XAttribute("ns3", ns3),
new XAttribute("ns2", ns2),
new XElement("requestId", Guid.NewGuid())
)
);
However, this produces the following:
<request ns4="http://www.example.com/a" ns3="http://www.example.com/b" ns2="http://www.example.com/c">
<requestId>38b07cfb-5e41-4d9a-97c8-4740c0432f11</requestId>
</request>
How do I add the namespace declarations correctly?
Do you mean:
new XAttribute(XNamespace.Xmlns + "ns4", ns4),
new XAttribute(XNamespace.Xmlns + "ns3", ns3),
new XAttribute(XNamespace.Xmlns + "ns2", ns2),

Categories

Resources