Il modo migliore per combinare i nodi con Html Agility Pack

c# html-agility-pack

Domanda

Ho convertito un documento di grandi dimensioni da Word a HTML. È vicino, ma ho un sacco di nodi "di codice" che vorrei unire in un nodo "pre".

Ecco l'input:

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

Voglio trasformarlo in questo, invece:

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

Ho finito per scrivere un ciclo di forza bruta che itera nodi alla ricerca di quelli consecutivi, ma questo mi sembra brutto:

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

Normalmente rimuoverei i nodi nel primo ciclo, ma ciò non funziona durante l'iterazione poiché non è possibile modificare la raccolta man mano che si itera su di essa.

Idee migliori?

Risposta popolare

Il primo approccio: selezionare tutti i nodi <code> , raggrupparli e creare un nodo <pre> per gruppo:

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

Il campo di raggruppamento qui è un campo combinato di un nodo genitore e un indice di gruppo che viene aumentato quando viene trovato un nuovo gruppo. Inoltre ho usato il metodo di estensione NextSiblingIsCode qui:

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

Utilizzato per determinare se il prossimo fratello è un nodo <code> .


Il secondo approccio: selezionare solo il nodo <code> cima a ciascun gruppo, quindi scorrere tutti questi nodi per trovare il prossimo nodo <code> fino al primo nodo non- <code> . Ho usato xpath qui:

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



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché