我当前正在创建一个程序来编辑由财务软件创建的xml文件。
我需要添加一个子树结构并为其添加一个特定值(这不是问题)。
我所苦的是了解XElement如何与名称空间一起使用。
子结构应如下所示:
<Id>
<OrgId>
<Othr>
<Id>VALUE</Id>
</Othr>
</OrgId>
</Id>
并且应该添加到文档中现有的子元素上,如下所示:
[...]
<InitgPty>
<Nm>SomeName</Nm>
//add substructure here
</InitgPty>
[...]
下面是我的第一个解决方案,它在从前一个元素(InitgPty-Element,如果我理解正确的话会从文档继承它的名称空间)中读取名称空间时,递归地构建树。
找到目标元素:
var ns = xDoc.Root.GetDefaultNamespace(); //xDoc is my XDocument which is read from file
var targetElement = xDoc.Descendants(
ns + "InitgPty" ).First();
函数调用:
BuildXmlSubTreeOnRoot(
targetElement, // this is the <InitgPtyElement>
new[]
{
"Id",
"OrgId",
"Othr"
} );
//the function
public XElement BuildXmlSubTreeOnRoot( XElement root, string[] args, int startIndex = 0 )
{
if (root == null)
{
return null;
}
else if( args.Length - startIndex > 0)
{
root.Add(
BuildXmlSubTreeOnRoot(
new XElement( root.GetDefaultNamespace() + args[startIndex]),
args.SubArray( ++startIndex, args.Length - startIndex ))
);
}
return root;
}
//Helper function subarray
public static class ArrayExtensions
{
public static T[] SubArray<T>( this T[] data, int index, int length )
{
T[] result = new T[length];
Array.Copy( data, index, result, 0, length );
return result;
}
}
那么,第一个根是<InitgPty>
(继承了文档名称空间,调试器显示了此信息),
然后将新的XElement作为子元素添加,而root.GetDefaultNamespace
提供名称空间。
然后,对新<Id>
子对象的递归调用应将<OrgId>
作为子元素添加到具有相同名称空间的<Id>
中。
但是GetDefaultNamespace()
上的<Id>
作为'root'返回一个空的XNamespace(调试器中为'{}')。
我完全不了解。如果有人可以帮助我了解这种行为,我将不胜感激。
现在,我发现(但不喜欢)一种解决方法是将名称空间直接传递给递归函数:
public XElement BuildXmlSubTreeOnRoot( XNamespace nameSpace, XElement root, string[] args, int startIndex = 0 )
{
if (root == null)
{
return null;
}
else if( args.Length - startIndex > 0)
{
root.Add(
BuildXmlSubTreeOnRoot(
nameSpace,
new XElement( nameSpace + args[startIndex]),
args.SubArray( ++startIndex, args.Length - startIndex ))
);
}
return root;
}
,然后传入我从XDocument先前检索到的名称空间
var ns = xDoc.Root.GetDefaultNamespace();
将其简化为一个问题:
为什么后者有效,而前者无效?
感谢您的帮助!