XElement-Namespaces (Gewusst wie?)

73

So erstellen Sie ein XML-Dokument mit einem Knotenpräfix wie:

<sphinx:docset>
  <sphinx:schema>
    <sphinx:field name="subject"/>
    <sphinx:field name="content"/>
    <sphinx:attr name="published" type="timestamp"/>
 </sphinx:schema>

Wenn ich versuche, so etwas wie new XElement("sphinx:docset")eine Ausnahme auszuführen

Nicht behandelte Ausnahme: System.Xml.XmlException: Das Zeichen ':', hexadezimaler Wert 0x3A, kann nicht in einen Namen aufgenommen werden.
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 expandName)

Edward83
quelle
Schauen Sie sich die XmlNamespaceManagerKlasse an.
13.
2
Ihr Dokument wäre ungültig. Es muss das sphinxPräfix deklarieren .
John Saunders

Antworten:

118

In LINQ to XML ist das ganz einfach:

XNamespace ns = "sphinx";
XElement element = new XElement(ns + "docset");

Oder damit der "Alias" richtig funktioniert, damit er wie Ihre Beispiele aussieht, ungefähr so:

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"))));

Das ergibt:

<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>
Jon Skeet
quelle
1
Danke, aber für die erste Version habe ich <docset xmlns = "sphinx" /> bekommen, es ist nicht was ich will;)))
Edward83
@ Edward83: Siehe mein anderes Beispiel. Grundsätzlich muss der Namespace irgendwo in xmlns angegeben werden ...
Jon Skeet
Nach all den hässlichen Hacks, die ich dazu verwendet habe (rekursive statische Methoden, um Namespace an alles anzuhängen) ... Ich habe diesen Ansatz zuerst versucht, aber XNamespace.Xmlns nicht dem äußeren Namespace vorangestellt. Warum ist dieses Präfix überhaupt notwendig? Setzt es es für global?
Micahhoover
@micahhoover: Sie sollten die W3C-Namespace-Spezifikation lesen. Mir ist nicht ganz klar, was Sie erreichen wollten oder was schief gelaufen ist.
Jon Skeet
22

Sie können den Namespace Ihres Dokuments lesen und in Abfragen wie diesen verwenden:

XDocument xml = XDocument.Load(address);
XNamespace ns = xml.Root.Name.Namespace;
foreach (XElement el in xml.Descendants(ns + "whateverYourElementNameIs"))
    //do stuff
Adam Rackis
quelle
1
Netter Ansatz (+1)! Dies funktionierte jedoch nicht für mich in einem Fall, in dem das XML-Stammelement mehrere xmlns-Attribute hatte, dh: xmlns: soapenv = "..." xmlns = "...". Mit xml.Root.GetDefaultNamespace () habe ich das bekommen, was ich wollte, nämlich den Wert des einfachen Attributs xmlns = "...".
Jon Schneider