Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Разбор XML, TXMLDocument

Автор вопроса: dedokiОтветов: 3

У меня проблема с разбором XML.

Как получить значения полей se_url и phrase?
Мне нужно получить link1_1, link1_2, key1, link2_1, link2_2, key2... которые находятся в se_url и phrase.

В гугле не нашел как это сделать (мануала по работе с TXMLDocument тоже не нашел).

<doc>
  <date2>20120214</date2>
  <date1>20120214</date1>
  <data count="116">
    <row>
      <search_engines count="2">
        <search_engine>
          <se_url>link1_1</se_url>
          <se_page>1</se_page>
          <se_id>2</se_id>
        </search_engine>
        <search_engine>
          <se_url>link1_2</se_url>
          <se_page>1</se_page>
          <se_id>3</se_id>
        </search_engine>
      </search_engines>
      <denial>0.4889</denial>
      <visits>45</visits>
      <page_views>52</page_views>
      <phrase>key1</phrase>
      <visit_time>126</visit_time>
      <depth>1.1556</depth>
    </row>
    <row>
      <search_engines count="2">
        <search_engine>
          <se_url>link2_1</se_url>
          <se_page>1</se_page>
          <se_id>3</se_id>
        </search_engine>
        <search_engine>
          <se_url>link2_2</se_url>
          <se_page>1</se_page>
          <se_id>6</se_id>
        </search_engine>
      </search_engines>
      <denial>0.5714</denial>
      <visits>42</visits>
      <page_views>50</page_views>
      <phrase>key2</phrase>
      <visit_time>109</visit_time>
      <depth>1.1905</depth>
    </row>
  </data>
</doc>
  • Извините, я понимаю, что английский, вероятно, не ваш родной язык, поскольку документ размещен в домене .ru, но этот вопрос не имеет никакого смысла. Не могли бы вы отредактировать его и предоставить более подробную информацию о том, что именно вы ищете? Mason Wheeler 14.02.2012
  • Публикация большей части вашего вопроса по ссылке за пределами сайта означает, что он становится бессмысленным, если этот другой сайт становится недоступным или исчезает. Пожалуйста, отредактируйте свой вопрос, предоставив здесь хотя бы часть XML-документа, чтобы ваш вопрос оставался полезным для других в будущем и был доступен для поиска. Пока вы редактируете эту часть, вы можете предоставить дополнительную информацию о том, что вы пытаетесь сделать и что вы пробовали до сих пор, и объяснить, почему это не сработало, как ожидалось. Спасибо. :0 Ken White 14.02.2012
  • dredei Я пытался показать вам, что имеет в виду Кен, надеюсь, мое редактирование поможет? Вы все равно должны расширить свой вопрос, чтобы сказать, что вы пробовали. Вы даже пробовали MSXML DOM или OmniXML, или вы просто пытались анализировать без парсера XML? Warren P 15.02.2012
  • @ Уоррен, вы только что убрали все стимулы для автора вернуться и отредактировать вопрос. (Вы сделали то же самое, что выполнили чье-то домашнее задание, а затем посоветовали ему прочитать книгу после этого.) Ken White 15.02.2012
  • обновил первый пост и поменял ссылку :) dedoki 15.02.2012
  • @dredei: не меняйте ссылку. Разместите здесь фрагмент XML, как мы просили несколько раз. Опять же, ссылки вне сайта не подходят - здесь ваш вопрос должен стоять сам по себе. Ken White 15.02.2012

xmlxml-parsingdelphitxmldocument

Ответы

Ответ 1 · рейтинг 21 · kobik

Попробуй это:

uses ComObj, MSXML;

procedure TForm1.Button1Click(Sender: TObject);
var
  xml: IXMLDOMDocument;
  node: IXMLDomNode;
  nodes_row, nodes_se: IXMLDomNodeList;
  i, j: Integer;
  url: string;
begin
  // put url or file name
  url := 'http://softez.pp.ua/gg.xml';

  xml := CreateOleObject('Microsoft.XMLDOM') as IXMLDOMDocument;
  xml.async := False;
  xml.load(url); // or use loadXML to load XML document using a supplied string
  if xml.parseError.errorCode <> 0 then
    raise Exception.Create('XML Load error:' + xml.parseError.reason);

  Memo1.Clear;
  nodes_row := xml.selectNodes('/doc/data/row');
  for i := 0 to nodes_row.length - 1 do
  begin
    node := nodes_row.item[i];
    Memo1.Lines.Add('phrase=' + node.selectSingleNode('phrase').text);
    nodes_se := node.selectNodes('search_engines/search_engine/se_url');
    for j := 0 to nodes_se.length - 1 do
    begin
      node := nodes_se.item[j];
      Memo1.Lines.Add('url=' + node.text);
    end;
    Memo1.Lines.Add('--------------');
  end;
end;

Результат:

phrase=key1
url=link1_1
url=link1_2
--------------
phrase=key2
url=link2_1
url=link2_2
--------------

Ссылка на IXMLDOMDocument

Ответ 2 · рейтинг 4 · Sean B. Durkin

Если вы сначала включите эти 3 подпрограммы библиотеки общего назначения....

uses XMLDoc, XMLIntf, xmldom;

function CreateXMLDocument( var Owner1: TComponent): TXMLDocument;
begin
Owner1 := TComponent.Create( nil);
result  := TXMLDocument.Create( Owner1);
result.Options := [doNodeAutoCreate, doNodeAutoIndent, doAttrNull,
                   doAutoPrefix, doNamespaceDecl];
result.DOMVendor := GetDOMVendor( 'MSXML');
end;

function XPATHSelect( const FocusNode: IXMLNode; const sXPath: string): TArray<IXMLNode>;
var
  DomNodeSelect: IDomNodeSelect;
  DOMNode      : IDomNode;
  DocAccess    : IXmlDocumentAccess;
  Doc          : TXmlDocument;
  DOMNodes     : IDOMNodeList;
  iDOMNode     : integer;
begin
SetLength( result, 0);
if assigned( FocusNode) and
   Supports( FocusNode.DOMNode, IDomNodeSelect, DomNodeSelect) then
    DOMNodes := DomNodeSelect.SelectNodes( sXPath);
if not assigned( DOMNodes) then exit;
SetLength( result, DOMNodes.Length);
for iDOMNode := 0 to DOMNodes.Length - 1 do
  begin
  Doc := nil;
  DOMNode := DOMNodes.item[iDOMNode];
  if Supports( DOMNode, IXmlDocumentAccess, DocAccess) then
    Doc := DocAccess.DocumentObject;
  result[ iDOMNode] := TXmlNode.Create( DOMNode, nil, Doc) as IXMLNode;
  end
end;


function XPATHSelectFirst( const FocusNode: IXMLNode; const sXPath: string; var SelectedNode: IXMLNode): boolean;
var
  DomNodeSelect: IDomNodeSelect;
  DOMNode      : IDomNode;
  DocAccess    : IXmlDocumentAccess;
  Doc          : TXmlDocument;
begin
SelectedNode := nil;
if assigned( FocusNode) and
   Supports( FocusNode.DOMNode, IDomNodeSelect, DomNodeSelect) then
  DOMNode := DomNodeSelect.selectNode( sXPath);
if assigned( DOMNode) and
   Supports( DOMNode.OwnerDocument, IXmlDocumentAccess, DocAccess) then
  Doc := DocAccess.DocumentObject;
if Assigned( DOMNode) then
  SelectedNode := TXmlNode.Create( DOMNode, nil, Doc);
result := assigned( SelectedNode)
end;

Тогда более изящным решением будет...

procedure TForm2.btn1Click(Sender: TObject);
const
  DocumentSource =  'http://softez.pp.ua/gg.xml';
var
  Doc: IXMLDocument;
  DocOwner: TComponent;
  RowNode, PhraseNode, UrlNode: IXMLNode;

  procedure PutLn( const LineFmt: string; const Args: array of const);
  begin
  memo2.Lines.Add( Format( LineFmt, Args))
  end;

begin
memo2.Clear;
Doc := CreateXMLDocument( DocOwner);
Doc.LoadFromFile( DocumentSource);
for RowNode in XPATHSelect( Doc.DocumentElement, '//row[phrase]') do
  begin
  if not XPATHSelectFirst( RowNode, 'phrase', PhraseNode) then continue;
  PutLn( 'phrase=%s', [PhraseNode.NodeValue]);
  for UrlNode in XPATHSelect( RowNode, 'search_engines/search_engine/se_url') do
    PutLn( 'url=%s', [UrlNode.NodeValue]);
  PutLn('--------------',[])
  end;
DocOwner.Free;
end;

Это было протестировано на Delphi 2010 и работает отлично.

Ответ 3 · рейтинг 4 · Sean B. Durkin

И на всякий случай вот еще один ответ, если вы не боитесь добавить немного XSLT!

const Transform =
'<?xml version="1.0" encoding="utf-8"?>' +
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> ' +
' <xsl:output method="text" indent="no"/>' +
' <xsl:template match="text()|@*"/>' +
' <xsl:template match="//row">' +
'  <xsl:text>phrase=</xsl:text>' +
'  <xsl:value-of select="phrase"/>' +
'  <xsl:text>&#10;</xsl:text>' +
'  <xsl:apply-templates/>' +
'  <xsl:text>--------------&#10;</xsl:text>' +
' </xsl:template>' +
' <xsl:template match="search_engines/search_engine/se_url">' +
'  <xsl:text>url=</xsl:text>' +
'  <xsl:value-of select="."/>' +
'  <xsl:text>&#10;</xsl:text>' +
' </xsl:template>' +
'</xsl:stylesheet>';


procedure TForm2.btn1Click( Sender: TObject);
const
  DocumentSource =  'http://softez.pp.ua/gg.xml';
var
  Doc, Style: IXMLDocument;
  DocOwner, StyleOwner: TComponent;
  sOut: widestring;
begin
  memo2.Clear;
  Doc := CreateXMLDocument( DocOwner);
  Doc.LoadFromFile( DocumentSource);
  Style := CreateXMLDocument( StyleOwner);
  Style.LoadFromXML( Transform);
  Doc.DocumentElement.TransformNode( Style.DocumentElement, sOut);
  memo2.Lines.Add( sOut);
  DocOwner.Free;
  StyleOwner.Free
end;

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы