【发布时间】:2013-02-19 12:57:49
【问题描述】:
考虑生成以下具有 2 个前缀命名空间的 XML 结构:
XNamespace ns1 = "http://www.namespace.org/ns1";
const string prefix1 = "w1";
XNamespace ns2 = "http://www.namespace.org/ns2";
const string prefix2 = "w2";
var root =
new XElement(ns1 + "root",
new XElement(ns1 + "E1"
, new XAttribute(ns1 + "attr1", "value1")
, new XAttribute(ns2 + "attr2", "value2"))
, new XAttribute(XNamespace.Xmlns + prefix2, ns2)
, new XAttribute(XNamespace.Xmlns + prefix1, ns1)
);
它会生成以下 XML 结果(这很好):
<w1:root xmlns:w2="http://www.namespace.org/ns2" xmlns:w1="http://www.namespace.org/ns1">
<w1:E1 w1:attr1="value1" w2:attr2="value2" />
</w1:root>
当我尝试通过注释掉其 XML 声明将 ns1 从前缀命名空间更改为默认命名空间时出现问题,如下所示:
var root =
new XElement(ns1 + "root",
new XElement(ns1 + "E1"
, new XAttribute(ns1 + "attr1", "value1")
, new XAttribute(ns2 + "attr2", "value2"))
, new XAttribute(XNamespace.Xmlns + prefix2, ns2)
//, new XAttribute(XNamespace.Xmlns + prefix1, ns1)
);
产生:
<root xmlns:w2="http://www.namespace.org/ns2" xmlns="http://www.namespace.org/ns1">
<E1 p3:attr1="value1" w2:attr2="value2" xmlns:p3="http://www.namespace.org/ns1" />
</root>
注意root 和E1 中重复的命名空间定义以及E1 下前缀为p3 的属性。我怎样才能避免这种情况发生?如何在根元素中强制声明默认命名空间?
相关问题
我研究了这个问题:How to set the default XML namespace for an XDocument
但建议的答案替换了没有定义任何命名空间的元素的命名空间。在我的示例中,元素和属性已经正确设置了它们的命名空间。
我尝试过的
基于太多的尝试和错误,在我看来,不直接在根节点下的属性,其中属性及其直接父元素都具有与默认命名空间相同的命名空间;需要删除属性的命名空间!!!
基于此,我定义了以下扩展方法,它遍历生成的 XML 的所有元素并执行上述操作。到目前为止,在我的所有示例中,此扩展方法都成功解决了问题,但这并不一定意味着有人不能为其生成失败的示例:
public static void FixDefaultXmlNamespace(this XElement xelem, XNamespace ns)
{
if(xelem.Parent != null && xelem.Name.Namespace == ns)
{
if(xelem.Attributes().Any(x => x.Name.Namespace == ns))
{
var attrs = xelem.Attributes().ToArray();
for (int i = 0; i < attrs.Length; i++)
{
var attr = attrs[i];
if (attr.Name.Namespace == ns)
{
attrs[i] = new XAttribute(attr.Name.LocalName, attr.Value);
}
}
xelem.ReplaceAttributes(attrs);
}
}
foreach (var elem in xelem.Elements())
elem.FixDefaultXmlNamespace(ns);
}
此扩展方法为我们的问题生成以下 XML,这正是我想要的:
<root xmlns:w2="http://www.namespace.org/ns2" xmlns="http://www.namespace.org/ns1">
<E1 attr1="value1" w2:attr2="value2" />
</root>
但是我不喜欢这个解决方案,主要是因为它很贵。我觉得我在某个地方错过了一个小环境。有什么想法吗?
【问题讨论】:
标签: c# linq-to-xml xml-namespaces