考虑生成以下 XML 结构,它有 2 个前缀命名空间:
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>
当我尝试ns1
通过注释掉其 XML 声明来将前缀命名空间更改为默认命名空间时,就会出现问题,如下所示:
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
前缀为p3
under的属性E1
。我怎样才能避免这种情况发生?如何强制在根元素中声明默认命名空间?
相关问题
我研究了这个问题: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>
但是我不喜欢这个解决方案,主要是因为它很贵。我觉得我在某个地方错过了一个小环境。有任何想法吗?