Лучший способ объединить узлы с Html Agility Pack - PullRequest
0 голосов
/ 04 августа 2010

Я преобразовал большой документ из Word в HTML.Это близко, но у меня есть куча узлов "кода", которые я хотел бы объединить в один узел "pre".

Вот входные данные:

<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>

Я хочу повернутьвместо этого:

<code><p>Here's a sample MVC Controller action:</p>
<pre class="brush: csharp">        public ActionResult Index()
    {
        return View();
    }

Начнем с внесения следующих изменений ...

В итоге я написал цикл перебора, который повторяетсяузлы ищут последовательные, но мне это кажется уродливым:

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();
}

Обычно я удаляю узлы в первом цикле, но это не работает во время итерации, так как вы не можете изменить коллекциюкак вы итерируете его.

Лучшие идеи?

Ответы [ 2 ]

2 голосов
/ 28 февраля 2012

Первый подход: выбрать все узлы <code>, сгруппировать их и создать узел <pre> для каждой группы:

<code>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.AppendChild (doc.CreateTextNode (string.Join (Environment).NewLine, group.Select (g => g.InnerText)))); group.Key.Parent.InsertBefore (pre, group.First ()); foreach (код var в группе) 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 здесь:

<code>var nodes = doc.DocumentNode.SelectNodes(
    "//code[name(preceding-sibling::*[1])!='code']"
);
foreach (var node in nodes)
{
    var pre = HtmlNode.CreateNode("<pre class='brush: csharp'>
"); node.ParentNode.InsertBefore (pre, node); var content = string.Empty; var next = node; do {content + = next.InnerText + Environment.NewLine; var previous = next; next = next.SelectSingleNode ("follow-sibling :: * [1] [name () = 'code']"); previous.Remove ();} while (next! = Null);pre.AppendChild (doc.CreateTextNode (content.TrimEnd (Environment.NewLine.ToCharArray ())));}
0 голосов
/ 30 августа 2010

Очистить HTML, который вы хотите разобрать. HTML-теги полосы Agility Pack НЕ В белом списке

...