如何将特定的XElement移至C#中的上一个节点?

时间:2019-05-02 04:24:44

标签: c# .net xml

以下是我的XML:

<navMap>
    <navPoint><content src="Text/01_Cover.xhtml"/></navPoint>
    <navPoint><content src="Text/02_Titlepage.xhtml#Titlepage"/></navPoint>
    <navPoint><content src="Text/03_Copyright.xhtml#Copyright"/></navPoint>
    <navPoint><content src="Text/04_Contents.xhtml#Contents"/></navPoint>
    <navPoint><content src="Text/05_Part01.xhtml#Part01"/></navPoint>
    <navPoint>
        <content src="Text/06_Part02.xhtml#Part02"/>
        <navPoint><content src="Text/06_Part02.xhtml#h3_2-1"/></navPoint>
        <navPoint>
            <content src="Text/08_Chapter01.xhtml#Chapter01"/>
            <navPoint><content src="Text/08_Chapter01.xhtml#h3_4-1"/></navPoint>
        </navPoint>
    </navPoint>
    <navPoint>
        <content src="Text/07_Part03.xhtml#Part03"/>
        <navPoint><content src="Text/07_Part03.xhtml#h3_3-1"/></navPoint>
    </navPoint>
    <navPoint><content src="Text/09_Chapter02.xhtml#Chapter02"/></navPoint>
    <navPoint><content src="Text/10_Chapter03.xhtml#Chapter03"/></navPoint>
    <navPoint><content src="Text/11_Chapter04.xhtml#Chapter04"/></navPoint>
    <navPoint><content src="Text/12_Chapter05.xhtml#Chapter05"/></navPoint>
</navMap>

在此XML中,包含src的所有h3属性都是其各自父级的子级,其余都是单独的元素。

类似地,我想将所有章节移至其各自的部分元素,例如:

<navMap>
    <navPoint><content src="Text/01_Cover.xhtml"/></navPoint>
    <navPoint><content src="Text/02_Titlepage.xhtml#Titlepage"/></navPoint>
    <navPoint><content src="Text/03_Copyright.xhtml#Copyright"/></navPoint>
    <navPoint><content src="Text/04_Contents.xhtml#Contents"/></navPoint>
    <navPoint><content src="Text/05_Part01.xhtml#Part01"/></navPoint>
    <navPoint>
        <content src="Text/06_Part02.xhtml#Part02"/>
        <navPoint><content src="Text/06_Part02.xhtml#h3_2-1"/></navPoint>
        <navPoint>
            <content src="Text/08_Chapter01.xhtml#Chapter01"/>
            <navPoint><content src="Text/08_Chapter01.xhtml#h3_4-1"/></navPoint>
        </navPoint>
    </navPoint>
    <navPoint>
        <content src="Text/07_Part03.xhtml#Part03"/>
        <navPoint><content src="Text/07_Part03.xhtml#h3_3-1"/></navPoint>
        <navPoint><content src="Text/09_Chapter02.xhtml#Chapter02"/></navPoint>
        <navPoint><content src="Text/10_Chapter03.xhtml#Chapter03"/></navPoint>
        <navPoint><content src="Text/11_Chapter04.xhtml#Chapter04"/></navPoint>
        <navPoint><content src="Text/12_Chapter05.xhtml#Chapter05"/></navPoint>
    </navPoint>
</navMap>

我已经缩进来解释我的需要。我想到了类似的东西:

foreach (var element in xDoc.Root.Element("navMap").Elements())
{
    if (element.Element("content").Attribute("src").Value.Contains("_Chapter"))
    {
        var previousNode = element.PreviousNode;
        if (previousNode.Contains == "Part")
        {
            //Shift element to Part
        }
    }
}

问题是,这仅适用于下一个Chapter。如您在XML中所看到的,有多个Chapters,所以我想将Chapter下的每个Part移到Part。如果您注意到了,则Part02只有一个章节,因为它后面有一个新的Part03,所以Part03现在是一个新的父元素。从此以后,包含Chapter的所有元素都将是Part03的子元素,一旦不包含Chapter的元素出现,它将再次成为新的父元素。

1 个答案:

答案 0 :(得分:2)

虽然我仍然不太清楚这个问题,但我认为这符合您的要求:

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var document = XDocument.Load("input.xml");
        var points = document.Descendants("navPoint").ToList();

        XElement currentPart = null;
        foreach (var point in points)
        {
            var src = point.Element("content").Attribute("src").Value;
            if (src.Contains("#Part"))
            {
                currentPart = point;
            }
            else if (src.Contains("#Chapter"))
            {
                if (point.Parent != currentPart)
                {
                    point.Remove();
                    currentPart.Add(point);
                }
            }
        }
        document.Save("output.xml");
    }
}

这假定:

  • 每个navPoint元素都有一个带有content属性的src元素
  • 在第一章元素之前总是有一个part元素
  • 只需将章节元素移动到当前part元素的末尾