如何防止从.NET的XmlDocument输出的空白xmlns属性?


118

从.NET中的XmlDocument生成XML时,xmlns第一次插入没有关联名称空间的元素时,将出现空白属性;如何预防呢?

例:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root",
    "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner"));
Console.WriteLine(xml.OuterXml);

输出:

<root xmlns="whatever:name-space-1.0"><loner xmlns="" /></root>

所需输出:

<root xmlns="whatever:name-space-1.0"><loner /></root>

是否有适用于XmlDocument代码的解决方案,不是将文档转换为字符串发生的事情OuterXml

我这样做的理由是看我是否可以使用XmlDocument生成的XML匹配特定协议的标准XML。blank xmlns属性可能不会破坏或混淆解析器,但是在我对该协议所见到的任何用法中,它都不存在。

Answers:


111

多亏了Jeremy Lew的回答和更多的尝试,我找到了删除空白xmlns属性的方法:在创建任何希望有前缀的子节点时,请传递根节点的名称空间。在根目录使用没有前缀的名称空间意味着您需要在子元素上使用相同的名称空间,以便它们没有前缀。

固定代码:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root", "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner", "whatever:name-space-1.0")); 
Console.WriteLine(xml.OuterXml);

感谢大家对您的所有回答,这些回答使我朝着正确的方向前进!


1
恰恰。将<loner>元素放在“ whatever:name-space-1.0”命名空间中意味着在序列化时不会向其添加空的xmlns属性(将其放置在任何命名空间中)。如果需要刷新名称空间的工作方式,请查看jclark.com/xml/xmlns.htm
JeniT

2
当心:元素需要这个(或也许是更好doc.DocumentElement.NamespaceURI),但没有指定命名空间CreateAttribute(),你会得到xmlns:psomething哪怕是同一个URI。
杰森·克莱本

87

这是JeniT回答的一种变体(非常感谢!)

XmlElement new_element = doc.CreateElement("Foo", doc.DocumentElement.NamespaceURI);

这样就不必在任何地方复制或重复命名空间。


3
根据我的最佳回应。我们不必知道什么是文档默认名称空间(当我们不从头开始创建xml文件(即在读取和修改场景中)时,请使用full)。
MuiBienCarlota 2012年

11

如果<loner>样本XML中的元素没有xmlns默认的名称空间声明,则它将在whatever:name-space-1.0名称空间中而不是没有名称空间中。如果这是您想要的,则需要在该命名空间中创建元素:

xml.CreateElement("loner", "whatever:name-space-1.0")

如果您希望<loner>元素不包含在任何命名空间中,那么所生成的XML正是您所需要的,并且您不必担心xmlns为您自动添加的属性。


3
问题出在不兼容的XML解析器(通常来自Microsoft)无法解决xmnls =“”)。
Craig Trader

2
/。叫。他们希望他们的随机MS重击评论回来。

@W。Craig Trader-不能说我遇到了问题。例?
凯夫

1
正确,我不希望<loner />节点具有名称空间,但是我也不希望其具有空白的名称空间属性(xmlns)。我的推理只是看我是否可以匹配这样设置的特定协议的XML输出。
尼尔·C·奥布雷姆斯基

5
这不是随意扑打。Microsoft Updater应用程序块使用XML清单来确定要交付给客户端的内容。不幸的是,清单解析器无法处理xmlns =“”;我必须编写一个后处理器,以去除空的xmlns属性。
Craig Trader

7

由于root是在无前缀的命名空间中,因此必须像您的示例一样输出要取消命名空间的root的任何子代。解决方案是像这样为根元素添加前缀:

<w:root xmlns:w="whatever:name-space-1.0">
   <loner/>
</w:root>

码:

XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement( "w", "root", "whatever:name-space-1.0" );
doc.AppendChild( root );
root.AppendChild( doc.CreateElement( "loner" ) );
Console.WriteLine(doc.OuterXml);

谢谢,但是将名称空间添加到实际的根目录将破坏我与正在使用的特定协议相关的XML。
尼尔·C·奥布雷姆斯基

啊! 我更多地了解了您在说什么,并在编写自己的答案时将其考虑在内。感谢Jeremy
Neil C. Obremski

0

如果可能,创建一个序列化类,然后执行以下操作:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);

这样比较安全,如果确实需要更多控制,则可以使用属性来控制名称空间。


0

我已经通过使用工厂模式解决了这个问题。我为XElement对象创建了一个工厂。作为工厂实例化的参数,我指定了XNamespace对象。因此,每次工厂创建XElement时,都会自动添加名称空间。这是工厂代码:

internal class XElementFactory
{
    private readonly XNamespace currentNs;

    public XElementFactory(XNamespace ns)
    {
        this.currentNs = ns;
    }

    internal XElement CreateXElement(String name, params object[] content)
    {
        return new XElement(currentNs + name, content);
    }
}

1
OP正在询问XmlDocument,不是XDocument
约翰·桑德斯

0

是的,您可以阻止XmlElement中的XMLNS。首先创建时间到了:像那样

<trkpt lat="30.53597" lon="-97.753324" xmlns="">
    <ele>249.118774</ele>
    <time>2006-05-05T14:34:44Z</time>
</trkpt>

更改代码:并像这样传递xml名称空间

C#代码:

XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.