我在寻找一种使用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>
什么会做这样的事情的最好方法?
绝对不是正则表达式 。 (注:这是最初的问题,现在去除的标签。)我通常不是一个跳跃上的小马是即将行列,但是这是一个情况,即正则表达式将是特别糟糕。
首先,我会写一个递归函数,消除遵循一个节点的所有兄弟节点称之为RemoveSiblingsAfter(node)
-然后自称其母公司 ,因此跟在父母兄弟姐妹都被删除,以及(和所有的兄弟姐妹继祖父母,依此类推)。 您可以使用XPath来查找您要来拆分节点(一个或多个), 例如 doc.DocumentNode.SelectNodes("//a[@href='#']")
并调用该节点上的功能。 完成后,你会删除分割节点本身,这就是它。 你会重复这些步骤原始文件的副本,除非你实现RemoveSiblingsBefore(node)
移除之前的一个节点的兄弟姐妹。
在你的榜样, RemoveSiblingsBefore
将如下行动:
-
<a href="#">
没有兄弟姐妹,所以递归上父, <li>
-
<li>
具有前述sibling- <li>Bullet 1</li>
-SO除去,并递归上父, <ul>
-
<ul>
没有兄弟姐妹,所以递归上父, <p>
-
<p>
具有前述sibling- <p>Stuff</p>
-SO除去,并在父,递归<div>
- 等等。
以下是我想出了。 这确实分离并去除其中分裂发生的元素的“空”的元素。
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;
}