XElement namespaces (How to?)
Asked Answered
K

3

76

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)

Karren answered 13/2, 2011 at 18:24 Comment(2)
Have a look into the XmlNamespaceManager class.Tamis
Your document would be invalid. It needs to declare the sphinx prefix.Tema
M
125

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>
Mc answered 13/2, 2011 at 18:31 Comment(4)
thank you, but for first version I got <docset xmlns="sphinx" /> it is not what I want;)))Karren
@Edward83: See my other example. Basically you'll need the namespace to be specified in xmlns somewhere...Mc
After all the ugly hacks I've used to do this (recursive static methods to attach namespace to everything) ... I tried this approach first, but I didn't prefix XNamespace.Xmlns to the outer namespace. Why is that prefix even necessary? Does it set it for global?Emelda
@micahhoover: You should read the W3C namespacing specification. It's not entirely clear to me what you were trying to achieve, or what went wrong.Mc
C
22

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
Curvilinear answered 13/2, 2011 at 18:35 Comment(1)
Nice approach (+1)! However, this didn't work for me in a case where the root XML element had multiple xmlns attributes, i.e.: xmlns:soapenv="..." xmlns="...". Using xml.Root.GetDefaultNamespace() did get me what I wanted, which was the value of the plain xmlns="..." attribute.Theft
N
-1

Step by step using LINQ to XML:

XNamespace ns = "http://url/for/sphinx";
XAttribute sphinx = new XAttribute(XNamespace.Xmlns + "sphinx", ns);
XElement docset = new XElement(ns + "docset", sphinx);               

XElement schema = new XElement(ns + "schema"); 
docset.Add(schema);

XElement field1 = new XElement(ns + "field", new XAttribute("name", "subject"));
XElement field2 = new XElement(ns +  "field", new XAttribute("name", "content"));
XElement attr = new XElement(ns + "attr",
    new XAttribute("name", "published"),
    new XAttribute("type", "timestamp"));

schema.Add(field1, field2, attr);  

Console.WriteLine(docset);

Output:

<sphinx:docset xmlns:sphinx="http://url/for/sphinx">
  <sphinx:schema>
    <sphinx:field name="subject" />
    <sphinx:field name="content" />
    <sphinx:attr name="published" type="timestamp" />
  </sphinx:schema>
</sphinx:docset>
Negligible answered 29/9, 2023 at 14:48 Comment(2)
Thas is basically the same as the accepted answer.Unerring
@Unerring It is step by step solution, namespace is added first and then created the whole xml. In accepted answer xml is created by one line of code and it is difficult to understand how to add namespace alias to big xmls.Negligible

© 2022 - 2024 — McMap. All rights reserved.