Delphi XE & OmniXML: Использование SelectNode ()? - PullRequest
2 голосов
/ 01 апреля 2011

У меня есть следующий фрагмент XML как часть большого файла XML, который я обрабатываю с использованием последнего снимка OmniXML:

<OrderRequestHeader>
<!-- snipped XML bits here -->
<ShipTo>                                                        
    <Address addressID="">                                      
        <Name xml:lang="en">SOME COMPANY</Name>        
        <PostalAddress name="default">                          
            <DeliverTo>John Doe</DeliverTo>                  
            <Street>123 Any St</Street>                  
            <City>Nowhere</City>                              
            <State>AK</State>                                   
            <PostalCode>99999</PostalCode>                      
            <Country isoCountryCode="US">United States</Country>
        </PostalAddress>                                        
        <Email/>                                                
        <Phone>                                                 
            <TelephoneNumber>                                   
                <CountryCode isoCountryCode=""/>                
                <AreaOrCityCode/>                               
                <Number></Number>                               
            </TelephoneNumber>                                  
        </Phone>                                                
    </Address>                                                  
</ShipTo>
<!-- more XML stuff follows -->
</OrderRequestHeader>

В настоящее время у меня есть переменная, указывающая на узел <ShipTo>, и я хочу выбрать содержимое узла <Name>. Я использую следующий код, но Node2 идет Nil ...

procedure ProcessXML;
var
    Node1, Node2: IXMLNode;

begin
    Node1 := FindNode(OrderHeader, 'ShipTo');
    // the above is working.  Node points to the <ShipTo> node
    Node2 := SelectNode(Node1, 'Name');
    // the above line doesn't work.  Node2 is Nil
end;

Почему Node2 Nil? Согласно справке в OmniXMLUtils.pas, SelectNode выберет один узел, возможно, более чем на один уровень ниже. Там определенно есть <Name> узел. Даже попытка найти узел через XPathSelect(Node1, 'Name'); возвращает пустой список. Я неправильно использую OmniXML? Можно ли добраться до узла <Name> без предварительного выбора узла <Address>?

Ответы [ 2 ]

1 голос
/ 01 апреля 2011

SelectNode работает нормально, если вы ставите символы двойной косой черты:

var
  FXMLDocument: IXMLDocument;

// Somewhere along the line
  FXMLDocument := CreateXMLDocument
  XMLLoadFromFile(FXMLDocument, 'WhateverFile.xml');
  // or XMLLoadFromAnsiString(FXMLDocument, SomeStringVar);


var
  QryNode, Node: IXMLNode;
begin
  QryNode := FXMLDocument.DocumentElement;
  Node := SelectNode(QryNode, 'ShipTo');
  if Assigned(Node) then
  begin
    QryNode := SelectNode(Node, '//Name');
    if Assigned(QryNode) then
      ShowMessage('ShipTo Name is ' + QryNode.FirstChild.Text)
    else
      ShowMessage('Name not found');
  end;
end;

Если вы предпочитаете, XPath также работает отлично:

implementation

var
  FXMLDocument: IXMLDocument;

// Somewhere along the line
  FXMLDocument := CreateXMLDocument
  XMLLoadFromFile(FXMLDocument, 'WhateverFile.xml');
  // or XMLLoadFromAnsiString(FXMLDocument, SomeStringVar);

function GetShipTo: string;
var
  QryNode: IXMLNode;
  Node: IXMLNode;
  NodeList: IXMLNodeList;
begin
  Result := '';
  QryNode := FXMLDocument.DocumentElement;  

  // The following also work:
  // '//Address/Name'
  // '//Name'
  NodeList := XPathSelect(QryNode, '//ShipTo/Address/Name');
  if NodeList.Length > 0 then
    QryNode := NodeList.Item[0]
  else
    QryNode := nil;
  if Assigned(QryNode) then
    Result := QryNode.FirstChild.Text; // Now has 'SOME COMPANY'
end;
0 голосов
/ 01 апреля 2011

Я понял, что я делаю неправильно: мне нужно указать весь относительный путь, а не только имя нужного мне узла внука.

Из приведенного выше примера ProcessXML я должен заполнитьв Node2 примерно так:

Node2 := SelectNode(Node, 'Address/Name');

Используя XPath, я должен найти его через XPathSelect(Node, 'Address/Name');

...