递归创建XML树时,父名称空间会丢失

时间:2018-07-24 11:06:17

标签: c# xml xml-namespaces

问题

我当前正在创建一个程序来编辑由财务软件创建的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();

将其简化为一个问题:
为什么后者有效,而前者无效?

感谢您的帮助!

0 个答案:

没有答案