是否可以创建具有两个 xml 名称空间的 XmlElement?

Is it possible to create an XmlElement with two xml namespaces?

我必须像下面这样生成 XML:

<foo:document xmlns="http://www.example.com/xmlns" xmlns:foo="http://www.example.com/xmlns/foo-version1">
    <foo:bar foo:baz="true" />
</foo:document>

如何在 c# 中使用 System.Xml.XmlDocument 生成此文档?

Net 库希望默认命名空间(不带前缀)是最后一个命名空间。我通常只使用限制较少的 Parse 方法。请参阅下面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml = "<foo:document xmlns=\"http://www.example.com/xmlns\" xmlns:foo=\"http://www.example.com/xmlns/foo-version1\">" +
                         "   <foo:bar foo:baz=\"true\" />" +
                         "</foo:document>";

            XDocument doc = XDocument.Parse(xml);
        }
    }
}

您可以按如下方式进行:

var fooNs = "http://www.example.com/xmlns/foo-version1";
var defNs = "http://www.example.com/xmlns";

var doc = new XmlDocument();

// Create and add the root element
var root = doc.CreateElement("foo", "document", fooNs);
doc.AppendChild(root);

// Add the default namespace (do note the root element is not in this namespace)
var defAttr = doc.CreateAttribute("xmlns");
defAttr.Value = defNs;
root.Attributes.Append(defAttr);

// Create the <foo:bar> element
var bar = doc.CreateElement("foo", "bar", fooNs);
var bazAttr = doc.CreateAttribute("foo", "baz", fooNs);
bazAttr.Value = XmlConvert.ToString(true);
bar.Attributes.Append(bazAttr);

// Add it to the root
root.AppendChild(bar);

备注:

  • 在命名空间中创建 XmlElementXmlAttribute 节点时,总是倾向于使用带有前缀、localName 和命名空间 URI 的 Create() 重载:


    从语义的角度来看,真正重要的是节点本地名称和命名空间;前缀只是在范围内查找名称空间声明的查找。

  • 注意我没有明确添加 xmlns:foo="http://www.example.com/xmlns/foo-version1" 属性?没有必要这样做,因为根元素是通过 doc.CreateElement("foo", "document", fooNs) 使用所需的命名空间和前缀创建的。框架 (XmlWriter) 将在将 XmlDocument 写入 XML.

    时自动发出 xmlns:foo 属性

    如果由于某种原因需要显式创建命名空间属性,可以按如下方式进行:

    // The following is redundant as the framework (XmlWriter) will add the necessary
    // xmlns:foo attribute as the XmlDocument is being written.  If you need to do it anway 
    // (e.g. to control the order) you can do it as follows.
    // (But note that XML attributes are unordered according to the XML specification, for details
    // see 
    var xmlnsNs = "http://www.w3.org/2000/xmlns/";
    
    var fooAttr = doc.CreateAttribute("xmlns", "foo", xmlnsNs);
    fooAttr.Value = fooNs;
    root.Attributes.Append(fooAttr);
    

演示 fiddle #1 here.

顺便说一句,正如评论中所写,使用 LINQ to XML:

更容易做到这一点
XNamespace fooNs = "http://www.example.com/xmlns/foo-version1";
XNamespace defNs = "http://www.example.com/xmlns";

var root = new XElement(fooNs + "document"
                        // Add the namespace declarations with your desired prefixes.  Be sure to pass them into the constructor.
                        , new XAttribute("xmlns", defNs.ToString())
                        , new XAttribute(XNamespace.Xmlns + "foo", fooNs.ToString())
                        // And add any required content.  The content can be passed into the constructor, or added later. 
                        , new XElement(fooNs + "bar", new XAttribute(fooNs + "baz", true)));

备注:

  • 使用 LINQ to XML,您 永远不会 需要担心 XElementXAttribute 的命名空间前缀.只需使用 XName 封装的正确命名空间和本地名称创建它们。框架 (XmlWriter) 将在写入时自动发出所有必要的命名空间属性。

    但是如果您出于某种原因确实需要配置名称空间,您可以构建适当的 XAttribute 对象,然后将它们传递给 XElement constructor

  • 如需进一步阅读,请参阅 How to: Create a Document with Namespaces (C#) (LINQ to XML)

演示 fiddle #2 here.