長さがすべてのHtmlAgilityPack部分文字列


質問

私は同じHTMLを返す必要がある入れ子になった要素(主にdivpの要素)を持つhtmlを持っていますが、与えられた文字数でsubstring'edします。明らかに、文字数は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>
    <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>

文字数(スペースを含む)の数は16であることに注意してください。後続の<div>は、 lengthが可変長に達したため削除lengthます。出力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>

更新

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

サンプル入力#2:

<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 maxLength = 7;与えられますint maxLength = 7;出力はいくつかのmoに等しくなければならない。 ParentNode = null場合、このコードのように動作しません:

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

InnterTextプロパティが読み込み専用であるため、新しいHtmlNodeの作成は役に立ちません。

受け入れられた回答

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

  1. 関連するテキストノードを選択し、それらのノードの長さの合計を計算します。
  2. 最大長を超えて実行中の合計に到達するために必要な数のノードを使用します。
  3. 手順## 1、2;で選択したノードの祖先であるノード以外のすべての要素ノードをドキュメントから削除します。
  4. 最大長に合わせてリストの最後のノードのテキストを切り取ってください。

UPDATE:これは最初のテキストノードで動作するはずです。おそらくTrim()は以下のように空白を削除する必要があります。

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




ライセンスを受けた: CC-BY-SA
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ