길이가 모두 인 HtmlAgilityPack 하위 문자열

c# html-agility-pack

문제

중첩 된 요소 (주로 divp 요소)를 html로 가지고 있는데, 동일한 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입니다. 글자 수가 가변 length 도달했기 때문에 후속 <div> 는 삭제됩니다. 출력 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; 출력은 몇 개월 과 동일해야합니다. 이 코드 때문에 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. 관련 텍스트 노드를 선택하고 해당 텍스트 노드의 누적 합계를 계산하십시오.
  2. 최대 길이를 초과하여 실행중인 총계에 도달하는 데 필요한만큼 노드를 가져옵니다.
  3. 단계 ## 1, 2 단계에서 선택한 노드의 조상 인 요소 노드를 제외하고 문서에서 모든 요소 노드를 제거합니다.
  4. 최대 길이에 맞게 목록의 마지막 노드에서 텍스트를 자릅니다.

업데이트 : 이것은 첫 번째 텍스트 노드와 함께 계속 작동해야합니다. 아마도 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 with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.