1

ネストされた要素(ほとんどはdiv要素とp要素のみ)を持つhtmlがありますが、同じhtmlを返す必要がありますが、指定された数の文字で部分文字列が付けられています。明らかに、文字数はhtmlタグを介して列挙するのではなく、各html要素のInnerTextの文字のみを数える必要があります。Htmlの結果は、適切な構造(有効なhtmlを維持するための終了タグ)を保持する必要があります。

サンプル入力:

<div>
    <p>some text</p>
    <p>some more text some more text some more text some more text some more text</p>
    <div>
        <p>some more text some more text some more text some more text some more text</p>
        <p>some more text some more text some more text some more text some more text</p>
    </div>
</div>

与えられint length = 16た出力は次のようになります。

<div>
    <p>some text</p> // 9 characters in the InnerText here
    <p>some mo</p> // 7 characters in the InnerText here; 9 + 7 = 16;
</div>

文字数(スペースを含む)が16であることに注意してください。文字数<div>が変数に達したため、後続の文字は削除されますlength。出力htmlはまだ有効であることに注意してください。

私は以下を試しましたが、それは実際には機能しません。出力は期待どおりではありません。一部のhtml要素が繰り返されます。

public static string SubstringHtml(this string html, int length)
{
    HtmlDocument doc = new HtmlDocument();
    doc.LoadHtml(html);
    int totalLength = 0;
    StringBuilder output = new StringBuilder();
    foreach (var node in doc.DocumentNode.Descendants())
    {
        totalLength += node.InnerText.Length;
        if(totalLength >= length)
        {
            int difference = totalLength - length;
            string lastPiece = node.InnerText.ToString().Substring(0, difference);
            output.Append(lastPiece);
            break;
        }
        else
        {
            output.Append(node.InnerHtml);
        }
    }
    return output.ToString();
}

アップデート

@SergeBelovは、最初のサンプル入力で機能するソリューションを提供しましたが、さらにテストを行うと、以下のような入力で問題が発生しました。

サンプル入力#2:

some more text some more text 
<div>
    <p>some text</p>
    <p>some more text some more text some more text some more text some more text</
</div>

その変数が与えられると、出力はあるmoint maxLength = 7;に等しくなるはずです。このコードのため、そのようには機能しません:ParentNode = null

lastNode
    .Node
    .ParentNode
    .ReplaceChild(HtmlNode.CreateNode(lastNodeText.InnerText.Substring(0, lastNode.NodeLength - lastNode.TotalLength + maxLength)), lastNode.Node);

新しいHtmlNodeを作成することは、そのInnterTextプロパティが読み取り専用であるため、役に立たないようです。

4

1 に答える 1

6

以下の小さなコンソールプログラムは、1つの可能なアプローチを示しています。

  1. 関連するテキストノードを選択し、それらの長さの現在の合計を計算します。
  2. 最大長を超えて現在の合計に到達するために必要な数のノードを取得します。
  3. 手順##1、2で選択したノードの祖先であるものを除いて、すべての要素ノードをドキュメントから削除します。
  4. リストの最後のノードのテキストを最大長に合うように切り取ります。

更新:これは、テキストノードが最初の場合でも機能するはずです。おそらく、Trim()以下のように空白を削除するにはaが必要です。

    static void Main(string[] args)
    {
        int maxLength = 9;
        string input = @"
            some more text some more text 
            <div>
                <p>some text</p>
                <p>some more text some more text some more text some more text some more text</
            </div>";

        var doc = new HtmlDocument();
        doc.LoadHtml(input);

        // Get text nodes with the appropriate running total
        var acc = 0;
        var nodes = doc.DocumentNode
            .Descendants()
            .Where(n => n.NodeType == HtmlNodeType.Text && n.InnerText.Trim().Length > 0)
            .Select(n => 
            {
                var length = n.InnerText.Trim().Length;
                acc += length;
                return new { Node = n, TotalLength = acc, NodeLength = length }; 
            })
            .TakeWhile(n => (n.TotalLength - n.NodeLength) < maxLength)
            .ToList();

        // Select element nodes we intend to keep
        var nodesToKeep = nodes
            .SelectMany(n => n.Node.AncestorsAndSelf()
                .Where(m => m.NodeType == HtmlNodeType.Element));

        // Select and remove element nodes we don't need
        var nodesToDrop = doc.DocumentNode
            .Descendants()
            .Where(m => m.NodeType == HtmlNodeType.Element)
            .Except(nodesToKeep)
            .ToList();

        foreach (var r in nodesToDrop)
            r.Remove();

        // Shorten the last node as required
        var lastNode = nodes.Last();
        var lastNodeText = lastNode.Node;
        var text = lastNodeText.InnerText.Trim().Substring(0,
                lastNode.NodeLength - lastNode.TotalLength + maxLength);
        lastNodeText
            .ParentNode
            .ReplaceChild(HtmlNode.CreateNode(text), lastNodeText);

        doc.Save(Console.Out);
    }
于 2012-12-10T03:50:03.927 に答える