2013-01-15 12 views
13

どのように解析できますか名前:&値 DIHtmlParserのタグ内のテキスト? Clever ComponentsのTCLHtmlParserで試してみましたが、失敗しました。 2番目の質問はDIHtmlParserが個々のタグを解析して、たとえばそのサブタグをループすることです。そのような単純な問題のためのその悪夢。HTMLタグの解析

<div class="tvRow tvFirst hasLabel tvFirst" title="example1"> 
    <label class="tvLabel">Name:</label> 
    <span class="tvValue">Value</span> 
<div class="clear"></div></div> 

<div class="tvRow tvFirst hasLabel tvFirst" title="example2"> 
    <label class="tvLabel">Name:</label> 
    <span class="tvValue">Value</span> 
<div class="clear"></div></div> 
+0

はStackOverflowのへようこそ。 AFAIKには、HTMLをJSONに変換する標準的な方法はありません。あなたの質問をより正確に編集し、有益な回答が期待される場合に達成しようとしていることのいくつかの例を提供してください。 – jachguate

+3

XHTML文書を無損失でJSON文書に変換できる何か*有能なものがあれば、実際に* JSONはもう必要ありません。 XHTMLインタプリタが直接生成した構造を使用してください。その時点では、HTMLからJSONへのコンバータは必要ありません。プログラムでドキュメントにアクセスできるHTMLライブラリが必要です。 –

+0

@RobKennedy JSONの解析は、XMLまたはHTMLより高速です。あなたのバブルを破棄して申し訳ありません。 :) –

答えて

14

あなたは、HTMLから何が必要要素解析するIHTMLDocument2 DOMを使用することができます。htmlp(デルファイドムHTMLパーサとコンバータ:

uses ActiveX, MSHTML; 

const 
    HTML = 
    '<div class="tvRow tvFirst hasLabel tvFirst" title="example1">' + 
    '<label class="tvLabel">Name:</label>' + 
    '<span class="tvValue">Value</span>' + 
    '<div class="clear"></div>' + 
    '</div>'; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    doc: OleVariant; 
    el: OleVariant; 
    i: Integer; 
begin 
    doc := coHTMLDocument.Create as IHTMLDocument2; 
    doc.write(HTML); 
    doc.close; 
    ShowMessage(doc.body.innerHTML); 
    for i := 0 to doc.body.all.length - 1 do 
    begin 
    el := doc.body.all.item(i); 
    if (el.tagName = 'LABEL') and (el.className = 'tvLabel') then 
     ShowMessage(el.innerText); 
    if (el.tagName = 'SPAN') and (el.className = 'tvValue') then 
     ShowMessage(el.innerText); 
    end; 
end; 

私は、私が今日見つけ、別の非常に素晴らしいHTMLパーサを言及したかったです)。これは明らかにIHTMLDocument2ほど柔軟ではありませんが、以前のDelphiバージョンではUnicodeをサポートしています。

使用例:

uses HtmlParser, DomCore; 

function GetDocBody(HtmlDoc: TDocument): TElement; 
var 
    i: integer; 
    node: TNode; 
begin 
    Result := nil; 
    for i := 0 to HtmlDoc.documentElement.childNodes.length - 1 do 
    begin 
    node := HtmlDoc.documentElement.childNodes.item(i); 
    if node.nodeName = 'body' then 
    begin 
     Result := node as TElement; 
     Break; 
    end; 
    end; 
end; 

procedure THTMLForm.Button2Click(Sender: TObject); 
var 
    HtmlParser: THtmlParser; 
    HtmlDoc: TDocument; 
    i: Integer; 
    body, el: TElement; 
    node: TNode; 
begin 
    HtmlParser := THtmlParser.Create; 
    try 
    HtmlDoc := HtmlParser.parseString(HTML); 
    try 
     body := GetDocBody(HtmlDoc); 
     if Assigned(body) then 
     for i := 0 to body.childNodes.length - 1 do 
     begin 
      node := body.childNodes.item(i); 
      if (node is TElement) then 
      begin 
      el := node as TElement; 
      if (el.tagName = 'div') and (el.GetAttribute('class') = 'tvRow tvFirst hasLabel tvFirst') then 
      begin 
       // iterate el.childNodes here... 
       ShowMessage(IntToStr(el.childNodes.length)); 
      end; 
      end; 
     end; 
    finally 
     HtmlDoc.Free; 
    end; 
    finally 
    HtmlParser.Free 
    end; 
end; 
+0

これはスレッドで動作しますか? –

+5

@ T0xic:確実にスレッドで動作しますが、CoInitializeを最初に呼び出すことを忘れないでください。 – whosrdaddy

+0

ああ、はい。 :)ありがとう! –

0

htmlファイルを処理するには、HTMLパーサーを使用します。

DIHtmlParserとなります。

RegExはパーサーではなく、HTMLからJSONへの変換は賢明な選択肢ではありません。

+1

DIHtmlParser?その非常に複雑なパーサです。 Clever ComponentsのTCLHtmlParserのようなものはありません。私はそれとその悪夢を使用しようとした。可用性は確かだが使いやすさは?恐ろしい.. –

0

一つもTHtmlFormatterとHTMLP parserの組み合わせを使用することができますし、OXml XPath parsing

uses 
    // Htmlp 
    HtmlParser, 
    DomCore, 
    Formatter, 
    // OXml 
    OXmlPDOM, 
    OXmlUtils; 

function HtmlToXHtml(const Html: string): string; 
var 
    HtmlParser: THtmlParser; 
    HtmlDoc: TDocument; 
    Formatter: THtmlFormatter; 
begin 
    HtmlParser := THtmlParser.Create; 
    try 
    HtmlDoc := HtmlParser.ParseString(Html); 
    try 
     Formatter := THtmlFormatter.Create; 
     try 
     Result := Formatter.GetText(HtmlDoc); 
     finally 
     Formatter.Free; 
     end; 
    finally 
     HtmlDoc.Free; 
    end; 
    finally 
    HtmlParser.Free; 
    end; 
end; 

type 
    TCard = record 
    Store: string; 
    Quality: string; 
    Quantity: string; 
    Price: string; 
    end; 
    TCards = array of TCard; 

function ParseCard(const Node: PXMLNode): TCard; 
const 
    StoreXPath = 'div[1]/ax'; 
    QualityXPath = 'div[3]'; 
    QuantityXPath = 'div[4]'; 
    PriceXPath = 'div[5]'; 
var 
    CurrentNode: PXMLNode; 
begin 
    Result := Default(TCard); 
    if Node.SelectNode(StoreXPath, CurrentNode) then 
    Result.Store := CurrentNode.Text; 
    if Node.SelectNode(QualityXPath, CurrentNode) then 
    Result.Quality := CurrentNode.Text; 
    if Node.SelectNode(QuantityXPath, CurrentNode) then 
    Result.Quantity := CurrentNode.Text; 
    if Node.SelectNode(PriceXPath, CurrentNode) then 
    Result.Price := CurrentNode.Text; 
end; 

procedure THTMLForm.OpenButtonClick(Sender: TObject); 
var 
    Html: string; 
    Xml: string; 
    FXmlDocument: IXMLDocument; 
    QueryNode: PXMLNode; 
    XPath: string; 
    NodeList: IXMLNodeList; 
    i: Integer; 
    Card: TCard; 
begin 
    Html := System.IOUtils.TFile.ReadAllText(FileNameEdit.Text, TEncoding.UTF8); 
    Xml := HtmlToXHtml(Html); 
    Memo.Lines.Text := Xml; 

    // Parse with XPath 
    FXMLDocument := CreateXMLDoc; 
    FXMLDocument.WriterSettings.IndentType := itIndent; 
    if not FXMLDocument.LoadFromXML(Xml) then 
    raise Exception.Create('Source document is not valid'); 
    QueryNode := FXmlDocument.DocumentElement; 
    XPath := '//div[@class="row pricetableline"]'; 
    NodeList := QueryNode.SelectNodes(XPath); 
    for i := 0 to NodeList.Count -1 do 
    begin 
    Card := ParseCard(NodeList[i]); 
    Memo.Lines.Text := Memo.Lines.Text + sLineBreak + 
     Format('%0:s %1:s %2:s %3:s', [Card.Store, Card.Quality, Card.Quantity, Card.Price]); 
    end; 

    Memo.SelStart := 0; 
    Memo.SelLength := 0; 
end;