htmldocument / HtmlAgilityPackを使用してすべてのノードとそのコンテンツを取得する

c# html html-agility-pack uwp

質問

私はHTMLからすべてのノードを取得し、次にそのノードからテキストとサブノードを取得し、同じサブノードから取得する必要があります。たとえば、私はこのHTMLを持っています:

<p>This <b>is a <a href="">Link</a></b> with <b>bold</b></p>

だから、私はpノードを取得する方法が必要です。フォーマットされていないテキスト(これ)、唯一の太字のテキスト( a )、太字のリンク( Link )、残りの書式付きの書式付きテキスト

私はhtmldocumentを使ってすべてのノードとサブノードを選択できることを知っていますが、どのようにしてサブノード、サブノード、およびテキスト/サブノードの前にテキストを取得して、レンダリングされたバージョンhtmlの( "これ 太字の リンクです")?

上記の例は単純なものであることに注意してください。 HTMLには、リスト、フレーム、番号付きリスト、トリプルフォーマットのテキストなど、より複雑なものがあります。レンダリングされたものは問題ではないことに注意してください。私はすでにそれをしましたが、別の方法で行っています。私が必要とするのは、ノードとそのコンテンツだけを取得する部分です。また、私はノードを無視できないので、何もフィルタリングすることはできません。そして、メインノードは、p、div、frame、ulなどで始めることができます。

受け入れられた回答

htmldocとそのプロパティを調べた後、@ HungCaoの観察のおかげで、私はHTMLコードを解釈する簡単な方法を得ました。

私のコードは例として追加するのが少し複雑ですので、私は軽いバージョンを投稿します。

まず、htmlDocをロードする必要があります。それはどんな機能でも可能です:

HtmlDocument htmlDoc = new HtmlDocument();
string html = @"<p>This <b>is a <a href="""">Link</a></b> with <b>bold</b></p>";
htmlDoc.LoadHtml(html);

次に、それぞれの "メイン"ノード(この場合はp)を解釈し、そのタイプに応じてLoopF​​unction(InterNode)をロードする必要があります。

HtmlNodeCollection nodes = htmlDoc.DocumentNode.ChildNodes;

foreach (HtmlNode node in nodes)
{
    if(node.Name.ToLower() == "p") //Low the typeName just in case
    {
        Paragraph newPPara = new Paragraph();
        foreach(HtmlNode childNode in node.ChildNodes)
        {
            InterNode(childNode, ref newPPara);
        }
        richTextBlock.Blocks.Add(newPPara);
    }
}

"NodeType"というプロパティがありますが、正しいタイプが返されないことに注意してください。代わりに、 "Name"プロパティを使用してください(htmlNodeのNameプロパティはHTMLのName属性と同じではありません)。

最後に、参照された(ref)段落にインラインを追加するInterNode関数があります

public bool InterNode(HtmlNode htmlNode, ref Paragraph originalPar)
{
    string htmlNodeName = htmlNode.Name.ToLower();

    List<string> nodeAttList = new List<string>();
    HtmlNode parentNode = htmlNode.ParentNode;
    while (parentNode != null) {
        nodeAttList.Add(parentNode.Name);
        parentNode = parentNode.ParentNode;
    } //we need to get it multiple types, because it could be b(old) and i(talic) at the same time.

    Inline newRun = new Run();
    foreach (string noteAttStr in nodeAttList) //with this we can set all the attributes to the inline
    {
        switch (noteAttStr)
        {
            case ("b"):
            case ("strong"):
                {
                    newRun.FontWeight = FontWeights.Bold;
                    break;
                }
            case ("i"):
            case ("em"):
                {
                    newRun.FontStyle = FontStyle.Italic;
                    break;
                }
        }
    }

    if(htmlNodeName == "#text") //the #text means that its a text node. Like <i><#text/></i>. Thanks @HungCao
    {
        ((Run)newRun).Text = htmlNode.InnerText;
    } else //if it is not a #text, don't load its innertext, as it's another node and it will always have a #text node as a child (if it has any text)
    {
        foreach (HtmlNode childNode in htmlNode.ChildNodes)
        {
            InterNode(childNode, ref originalPar);
        }
    }

    return true;
}

注:私は、私のアプリがWebViewとは別の方法でHTMLをレンダリングする必要があると言ったことを知っています。このサンプルコードはWebviewと同じものを生成しますが、これまで述べたように、私の最終的なコードのバージョン。実際、私のオリジナルの/完全なコードは私が必要とするように動作しており、これは単なるベースです。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow