我已将大型文档从Word转换为HTML。它很接近,但我有一堆“代码”节点,我想合并到一个“预”节点。
这是输入:
<p>Here's a sample MVC Controller action:</p>
<code> public ActionResult Index()</code>
<code> {</code>
<code> return View();</code>
<code> }</code>
<p>We'll start by making the following changes...</p>
我想把它变成这个,而不是:
<p>Here's a sample MVC Controller action:</p>
<pre class="brush: csharp"> public ActionResult Index()
{
return View();
}</pre>
<p>We'll start by making the following changes...</p>
我最后编写了一个暴力循环来迭代寻找连续节点的节点,但这对我来说似乎很难看:
HtmlDocument doc = new HtmlDocument();
doc.Load(file);
var nodes = doc.DocumentNode.ChildNodes;
string contents = string.Empty;
foreach (HtmlNode node in nodes)
{
if (node.Name == "code")
{
contents += node.InnerText + Environment.NewLine;
if (node.NextSibling.Name != "code" &&
!(node.NextSibling.Name == "#text" && node.NextSibling.NextSibling.Name == "code")
)
{
node.Name = "pre";
node.Attributes.RemoveAll();
node.SetAttributeValue("class", "brush: csharp");
node.InnerHtml = contents;
contents = string.Empty;
}
}
}
nodes = doc.DocumentNode.SelectNodes(@"//code");
foreach (var node in nodes)
{
node.Remove();
}
通常我会删除第一个循环中的节点,但这在迭代期间不起作用,因为在迭代时不能更改集合。
更好的想法?
答案 0 :(得分:2)
第一种方法:选择所有<code>
个节点,对它们进行分组,并为每个组创建一个<pre>
节点:
var idx = 0;
var nodes = doc.DocumentNode
.SelectNodes("//code")
.GroupBy(n => new {
Parent = n.ParentNode,
Index = n.NextSiblingIsCode() ? idx : idx++
});
foreach (var group in nodes)
{
var pre = HtmlNode.CreateNode("<pre class='brush: csharp'></pre>");
pre.AppendChild(doc.CreateTextNode(
string.Join(Environment.NewLine, group.Select(g => g.InnerText))
));
group.Key.Parent.InsertBefore(pre, group.First());
foreach (var code in group)
code.Remove();
}
此处的分组字段是父节点和组索引的组合字段,当找到新组时,该字段会增加。
我在这里也使用了NextSiblingIsCode
扩展方法:
public static bool NextSiblingIsCode(this HtmlNode node)
{
return (node.NextSibling != null && node.NextSibling.Name == "code") ||
(node.NextSibling is HtmlTextNode &&
node.NextSibling.NextSibling != null &&
node.NextSibling.NextSibling.Name == "code");
}
它用于确定下一个兄弟是否是<code>
节点。
<code>
节点,然后遍历每个节点以查找下一个<code>
节点,直到第一个非<code>
节点。我在这里使用xpath
:
var nodes = doc.DocumentNode.SelectNodes(
"//code[name(preceding-sibling::*[1])!='code']"
);
foreach (var node in nodes)
{
var pre = HtmlNode.CreateNode("<pre class='brush: csharp'></pre>");
node.ParentNode.InsertBefore(pre, node);
var content = string.Empty;
var next = node;
do
{
content += next.InnerText + Environment.NewLine;
var previous = next;
next = next.SelectSingleNode("following-sibling::*[1][name()='code']");
previous.Remove();
} while (next != null);
pre.AppendChild(doc.CreateTextNode(
content.TrimEnd(Environment.NewLine.ToCharArray())
));
}
答案 1 :(得分:0)
清理要解析的html。 HTML Agility Pack strip tags NOT IN whitelist