次の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
名前空間定義に注意してくださいE1
。これを回避するにはどうすればよいですか?ルート要素でデフォルトの名前空間の宣言を強制するにはどうすればよいですか?
関連する質問
私はこの質問を研究しました:XDocumentのデフォルトのXML名前空間を設定する方法
しかし、提案された答えは、名前空間が定義されていない要素の名前空間を置き換えます。私のサンプルでは、要素と属性にはすでに名前空間が正しく設定されています。
私が試したこと
試行錯誤が多すぎるため、ルートノードの直下にない属性は、属性とその直接の親要素の両方がデフォルトの名前空間と同じ名前空間を持っているように見えます。属性の名前空間を削除する必要があります!!!
これに基づいて、結果の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>
しかし、主に高価であるため、このソリューションは好きではありません。どこかに小さな設定が欠けているような気がします。何か案は?