Эффективный метод Delphi для анализа HTML-кода для данных

#html #parsing #delphi

Вопрос:

Иногда мне нужно анализировать такие данные, как эти:

 <tr>
  <td data-th="Name">
    John Smith
  </td>
  <td data-th="Phone">
    1234567
  </td>
  <td data-th="Postal">
    16803
  </td>
  <td data-th="Office Number">
    12345678
  </td>
  <td data-th="Remarks">
    Hello
  </td>
</tr>
<tr>
  <td data-th="Name">
    Mary Smith
  </td>
  <td data-th="Phone">
    1234589
  </td>
  <td data-th="Postal">
    16801
  </td>
  <td data-th="Office Number">
    2385234
  </td>
  <td data-th="Remarks">
    Hi There
  </td>
</tr>
 

Я бы сделал что-то вроде загрузки этого в TStringList :

 for i := 0 to oStringList.Count-1 do
begin
  if oStringList[i].Trim = '<tr>' then
  begin
    // start of record
  end else if oStringList[i].Trim = '</tr>' then
  begin 
    // end of record
  end else
  begin
    // part of record data
  end;
end;
 

Есть ли лучший способ сделать это, либо с помощью очень эффективного кода, либо уже существуют действительно хорошие компоненты Delphi (желательно бесплатные/с открытым исходным кодом), которые могут это сделать? Я видел поток (датированный более 3 лет назад) в stackoverflow, в котором упоминался компонент, просто интересно, появилось ли что-то лучшее.

Спасибо.

Обновление: попытка использовать компонент htmlp —> как настроить код для анализа приведенных выше данных… схематичный пример не помог. я хочу просмотреть каждый TR/TR и получить

   var HtmlParser: THtmlParser;
  var  HtmlDoc: TDocument;
  var  x: Integer;
  var  body, el: TElement;
  var  node: TNode;
  begin
    HtmlParser := THtmlParser.Create;
    try
      HtmlDoc := HtmlParser.parseString(memo1.Text);
      try
        body := GetDocBody(HtmlDoc);
        if Assigned(body) then
        for x := 0 to body.childNodes.length - 1 do
        begin
          node := body.childNodes.item(x);
          if (node is TElement) then
          begin
            el := node as TElement;
            if (el.tagName = 'td') then //and (el.GetAttribute('data-th') = 'Name') then
            begin
              // iterate el.childNodes here...
              //ShowMessage(IntToStr(el.childNodes.length));
              memo1.Lines.Add(IntToStr(el.childNodes.length));
            end else
            begin

            end;
          end else
          begin
            memo1.Lines.Add('node is not element');
          end;
        end;
      finally
        HtmlDoc.Free;
      end;
    finally
      HtmlParser.Free
    end;
  end;
 

Комментарии:

1. «Есть ли лучший способ сделать это[?]» Да, используйте синтаксический анализатор HTML. Однако мы не можем рекомендовать его, поскольку рекомендации по программному обеспечению явно запрещены правилами переполнения стека.

2. Тогда могу я спросить, является ли htmlp очень хорошим выбором, поскольку вы не можете рекомендовать?

3. Не ожидайте, что HTML будет состоять из нескольких строк — заполнение всего вместе без единого взлома строки является законным. Синтаксический анализатор (HTML), скорее всего, задохнется от синтаксических/логических ошибок (таких как ваши 2 </td> в ряд), к которым вам, как человеку, было бы легко адаптироваться, но, с другой стороны, он также, скорее всего, поддерживает сущности ( amp;< ) и многое другое, чего следует ожидать от HTML.

4. Это правда. Я исправил двойника </td> . могу я спросить, есть ли у кого-нибудь опыт работы с синтаксическим анализатором htmlp, чтобы знать, как анализировать в этом случае?

5. Зачем вам вообще нужен синтаксический анализ HTML?

Ответ №1:

Когда это хорошо сформированный HTML, подобный этому, где начальные записи также имеют конечные записи ( <TR>...</TR> ), тогда это в основном XML. Таким образом, вы можете использовать средство чтения XML для анализа документа.

Используя синтаксический анализатор XML kbmMW, как это:

 const
  HTML =
'  <tr>' 
'  <td data-th="Name">' 
'    John Smith' 
'  </td>' 
'  <td data-th="Phone">' 
'    1234567' 
'  </td>' 
'  <td data-th="Postal">' 
'    16803' 
'  </td>' 
'  <td data-th="Office Number">' 
'    12345678' 
'  </td>' 
'  <td data-th="Remarks">' 
'    Hello' 
'  </td>' 
'</tr>' 
'<tr>' 
'  <td data-th="Name">' 
'    Mary Smith' 
'  </td>' 
'  <td data-th="Phone">' 
'    1234589' 
'  </td>' 
'  <td data-th="Postal">' 
'    16801' 
'  </td>' 
'  <td data-th="Office Number">' 
'    2385234' 
'  </td>' 
'  <td data-th="Remarks">' 
'    Hi There' 
'  </td>' 
'</tr>';
    
procedure TForm1.Button1Click(Sender: TObject);
var
   xml:TkbmMWDOMXML;
   i,j:integer;
   nTR,nTD:TkbmMWDOMXMLNodeList;
   n1,n2:TkbmMWDOMXMLNode;
begin
     Memo1.Clear;
     xml:=TkbmMWDOMXML.Create(HTML);
     try
        nTR:=xml.Root.ChildrenByName['tr'];
        try
           for i:=0 to nTR.Count-1 do
           begin
                n1:=nTR.Nodes[i];
                nTD:=n1.ChildrenByName['td'];
                try
                   for j:=0 to nTD.Count-1 do
                   begin
                        n2:=nTD.Nodes[j];
                        Memo1.Lines.Add(n2.AttribByName['data-th'] '=' n2.Data);
                   end;
                finally
                   nTD.Free;
                end;
           end;
        finally
           nTR.Free;
        end;
     finally
        xml.Free;
     end;
end;
 

Приводит к этому:

 Name=John Smith
Phone=1234567
Postal=16803
Office Number=12345678
Remarks=Hello
Name=Mary Smith
Phone=1234589
Postal=16801
Office Number=2385234
Remarks=Hi There
 

Анализатор XML kbmMW включен, наряду со многим другим, в бесплатную версию сообщества, которую можно загрузить с https://portal.components4developers.com после регистрации.

Комментарии:

1. Разве html, который также является xml, не известен как xhtml

2. @DavidHeffernan Определенно да. HTML-это SGML, поэтому наиболее распространенным знаменателем является только часть «ML». HTML5 должно быть невозможно разобрать как XML, потому что отсутствующие закрывающие теги теперь легальны , поэтому этот ответ подразумевает HTML2 через 4 или XHTML1.

3. @питер Существует множество доступных синтаксических анализаторов XML, и многие из них имеют более разрешительные лицензии, чем анализатор Кима, который он продвигает здесь. Действительно, в стандартных библиотеках Delphi есть полнофункциональный синтаксический анализатор XML, которого должно быть более чем достаточно для удовлетворения ваших потребностей.

4. @KimMadsen мои извинения на днях, когда я увидел ваш ответ, сайт находился в процессе технического обслуживания, поэтому я не смог принять ответ как правильный.

5. @AmigoJack спасибо за ваш ответ