如何为XDocument设置默认的XML命名空间

Ant*_*ull 46 c#

如何设置现有XDocument的默认命名空间(因此我可以使用DataContractSerializer对其进行反序列化).我尝试了以下方法:

var doc = XDocument.Parse("<widget/>");
var attrib = new XAttribute("xmlns",
                            "http://schemas.datacontract.org/2004/07/Widgets");
doc.Root.Add(attrib);
Run Code Online (Sandbox Code Playgroud)

我得到的例外是 The prefix '' cannot be redefined from '' to 'http://schemas.datacontract.org/2004/07/Widgets' within the same start element tag.

有任何想法吗?

Mic*_*tum 50

不确定这是否已经在.net 3.5或仅在4中有效,但这对我来说很好:

XNamespace ns = @"http://mynamespace";
var result = new XDocument(
    new XElement(ns + "rootNode",
        new XElement(ns + "child",
            new XText("Hello World!")
         )
     )
 );
Run Code Online (Sandbox Code Playgroud)

产生这个文件:

<rootNode xmlns="http://mynamespace">
    <child>Hello World!</child>
</rootNode>
Run Code Online (Sandbox Code Playgroud)

重要的是始终使用ns + "NodeName"语法.

  • 这基本上是最好的答案.请注意,它通过"XNamespace"上的运算符重载来工作,因此(ns + name)返回指向_exact相同XNamespace对象的*XName*.不幸的是,你不能使用`XName.Get()`来做到这一点.它还对本地名称进行字符串实习,因此您不会在内存中结束太多字符串. (3认同)
  • 我使用这样的函数(先前已经设置了xmlns):`Func <string,XName> ns = s => xmlns + s;`然后总是使用`ns("MyNodeName")` (3认同)

R. *_*des 48

似乎Linq to XML没有为这个用例提供API(免责声明:我没有深入调查).如果更改根元素的名称空间,如下所示:

XNamespace xmlns = "http://schemas.datacontract.org/2004/07/Widgets";
doc.Root.Name = xmlns + doc.Root.Name.LocalName;
Run Code Online (Sandbox Code Playgroud)

只有root元素的名称空间才会更改.所有孩子都有一个明确的空xmlns标记.

解决方案可能是这样的:

public static void SetDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
    if(xelem.Name.NamespaceName == string.Empty)
        xelem.Name = xmlns + xelem.Name.LocalName;
    foreach(var e in xelem.Elements())
        e.SetDefaultXmlNamespace(xmlns);
}

// ...
doc.Root.SetDefaultXmlNamespace("http://schemas.datacontract.org/2004/07/Widgets");
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢不改变现有文档的版本:

public XElement WithDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
    XName name;
    if(xelem.Name.NamespaceName == string.Empty)
        name = xmlns + xelem.Name.LocalName;
    else
        name = xelem.Name;
    return new XElement(name,
                    from e in xelem.Elements()
                    select e.WithDefaultXmlNamespace(xmlns));
}
Run Code Online (Sandbox Code Playgroud)

  • 认真.什么是字面上最常见的用例不受支持? (8认同)

Nap*_*ppy 6

我有同样的要求,但我提出了一些不同的东西:

/// <summary>
/// Sets the default XML namespace of this System.Xml.Linq.XElement
/// and all its descendants
/// </summary>
public static void SetDefaultNamespace(this XElement element, XNamespace newXmlns)
{
    var currentXmlns = element.GetDefaultNamespace();
    if (currentXmlns == newXmlns)
        return;

    foreach (var descendant in element.DescendantsAndSelf()
        .Where(e => e.Name.Namespace == currentXmlns)) //!important
    {
        descendant.Name = newXmlns.GetName(descendant.Name.LocalName);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要正确执行,则必须考虑,您的元素可能包含不同命名空间的扩展元素.您不希望全部更改它们,而只想更改那些默认的命名空间元素.