拆分HTML字符串转换成两个部分HtmlAgilityPack(Splitting HTML str

2019-10-19 00:24发布

我在寻找一种使用HtmlAgilityPack在C#中的一些标签来分割HTML文档的最佳方式。 我想保留预期的标记,因为我正在做的分裂。 下面是一个例子。

如果该文件是这样的:

<p>
<div>
    <p>
        Stuff
    </p>
    <p>
        <ul>
            <li>Bullet 1</li>
            <li><a href="#">link</a></li>
            <li>Bullet 3</li>
        </ul>
    </p>
            <span>Footer</span>
</div>
</p>

一旦它的分裂,它应该是这样的:

第1部分

<p>
<div>
    <p>
        Stuff
    </p>
    <p>
        <ul>
            <li>Bullet 1</li>
        </ul>
    </p>
</div>
</p>

第2部分

<p>
<div>
    <p>
        <ul>
            <li>Bullet 3</li>
        </ul>
    </p>
            <span>Footer</span>
</div>

</p>

什么会做这样的事情的最好方法?

Answer 1:

绝对不是正则表达式 。 (注:这是最初的问题,现在去除的标签。)我通常不是一个跳跃上的小马是即将行列,但是这是一个情况,即正则表达式将是特别糟糕。

首先,我会写一个递归函数,消除遵循一个节点的所有兄弟节点称之为RemoveSiblingsAfter(node) -然后自称母公司 ,因此跟在父母兄弟姐妹都被删除,以及(和所有的兄弟姐妹继祖父母,依此类推)。 您可以使用XPath来查找您要来拆分节点(一个或多个), 例如 doc.DocumentNode.SelectNodes("//a[@href='#']")并调用该节点上的功能。 完成后,你会删除分割节点本身,这就是它。 你会重复这些步骤原始文件的副本,除非你实现RemoveSiblingsBefore(node)移除之前的一个节点的兄弟姐妹。

在你的榜样, RemoveSiblingsBefore将如下行动:

  1. <a href="#">没有兄弟姐妹,所以递归上父, <li>
  2. <li>具有前述sibling- <li>Bullet 1</li> -SO除去,并递归上父, <ul>
  3. <ul>没有兄弟姐妹,所以递归上父, <p>
  4. <p>具有前述sibling- <p>Stuff</p> -SO除去,并在父,递归<div>
  5. 等等。


Answer 2:

以下是我想出了。 这确实分离并去除其中分裂发生的元素的“空”的元素。

    private static void SplitDocument()
    {
        var doc = new HtmlDocument();
        doc.Load("HtmlDoc.html");
        var links = doc.DocumentNode.SelectNodes("//a[@href]");
        var firstPart = GetFirstPart(doc.DocumentNode, links[0]).DocumentNode.InnerHtml;
        var secondPart = GetSecondPart(links[0]).DocumentNode.InnerHtml;
    }

    private static HtmlDocument GetFirstPart(HtmlNode currNode, HtmlNode link)
    {
        var nodeStack = new Stack<Tuple<HtmlNode, HtmlNode>>();        
        var newDoc = new HtmlDocument();
        var parent = newDoc.DocumentNode;

        nodeStack.Push(new Tuple<HtmlNode, HtmlNode>(currNode, parent));

        while (nodeStack.Count > 0)
        {
            var curr = nodeStack.Pop();
            var copyNode = curr.Item1.CloneNode(false);
            curr.Item2.AppendChild(copyNode);

            if (curr.Item1 == link)
            {
                var nodeToRemove = NodeAndEmptyAncestors(copyNode);
                nodeToRemove.ParentNode.RemoveChild(nodeToRemove);
                break;
            }

            for (var i = curr.Item1.ChildNodes.Count - 1; i >= 0; i--)
            {
                nodeStack.Push(new Tuple<HtmlNode, HtmlNode>(curr.Item1.ChildNodes[i], copyNode));
            }
        }

        return newDoc;
    }

    private static HtmlDocument GetSecondPart(HtmlNode link)
    {
        var nodeStack = new Stack<HtmlNode>();
        var newDoc = new HtmlDocument();

        var currNode = link;
        while (currNode.ParentNode != null)
        {
            currNode = currNode.ParentNode;
            nodeStack.Push(currNode.CloneNode(false));
        }

        var parent = newDoc.DocumentNode;
        while (nodeStack.Count > 0)
        {
            var node = nodeStack.Pop();
            parent.AppendChild(node);
            parent = node;
        }

        var newLink = link.CloneNode(false);
        parent.AppendChild(newLink);

        currNode = link;
        var newParent = newLink.ParentNode;

        while (currNode.ParentNode != null)
        {
            var foundNode = false;
            foreach (var child in currNode.ParentNode.ChildNodes)
            {
                if (foundNode) newParent.AppendChild(child.Clone());
                if (child == currNode) foundNode = true;
            }

            currNode = currNode.ParentNode;
            newParent = newParent.ParentNode;
        }

        var nodeToRemove = NodeAndEmptyAncestors(newLink);
        nodeToRemove.ParentNode.RemoveChild(nodeToRemove);

        return newDoc;
    }

    private static HtmlNode NodeAndEmptyAncestors(HtmlNode node)
    {
        var currNode = node;
        while (currNode.ParentNode != null && currNode.ParentNode.ChildNodes.Count == 1)
        {
            currNode = currNode.ParentNode;
        }

        return currNode;
    }


文章来源: Splitting HTML string into two parts with HtmlAgilityPack