delphi xpath xml query

前端 未结 4 497
温柔的废话
温柔的废话 2021-01-01 03:15

I\'m trying to locate the value for in the following XML File using a XPath query.



        
4条回答
  •  长情又很酷
    2021-01-01 04:10

    Martijn mentioned about the Vendor property in a comment to his answer.

    The property is in fact called DOMVendor.

    Further below is some sample code that shows how that works.
    The sample code depends on some helper classes you can find on bo.codeplex.com.

    Note that DOMVendor will not tell you what version of MSXML you have, but you can ask it if it has XPath support.

    Old MSXML versions (that are still in the field, for instance on plain vanilla Windows 2003 Server installations) won't support XPath, but support XSLPattern.
    They will happily execute your queries, but sometimes return different results, or barf.

    There are some sublte bugs in various sub-versions of MSXML6 too.
    You need 6.30., 6.20.1103., 6.20.2003.0 or higher. 6.3 is only available on Windows 7/Windows 2008 Server. The 6.20 flavours on Windows XP and Windows 2003 Server.
    Finding out which versions actually work took me a quite some time :-)

    This shows you the installed MSXML, in my case msxml6.dll: 6.20.1103.0:

    procedure TMainForm.ShowMsxml6VersionClick(Sender: TObject);
    begin
    {
    Windows 2003 with MSXML 3: msxml3.dll: 8.100.1050.0
    
    windows XP with MSXML 4: msxml4.dll: 4.20.9818.0
    
    Windows XP with MSXML 6 SP1: msxml6.dll: 6.10.1129.0
    
    windows XP with MSXML 6 SP2 (latest):
    ------------------------
    msxml6.dll: 6.20.1103.0
    
    Windows 7 with MSXML 6 SP3:
    --------------------------
    msxml6.dll: 6.30.7600.16385
    }
      try
        Logger.Log(TmsxmlFactory.msxmlBestFileVersion.ToString());
        TmsxmlFactory.AssertCompatibleMsxml6Version();
      except
        on E: Exception do
        begin
          Logger.Log('Error');
          Logger.Log(E);
        end;
      end;
    end;
    

    This shows the DOMVendor code, it makes some use of helper classes, you can find that on

    procedure TMainForm.FillDomVendorComboBox;
    var
      DomVendorComboBoxItemsCount: Integer;
      Index: Integer;
      CurrentDomVendor: TDOMVendor;
      DefaultDomVendorIndex: Integer;
      CurrentDomVendorDescription: string;
    const
      NoSelection = -1;
    begin
      DomVendorComboBox.Clear;
      DefaultDomVendorIndex := NoSelection;
      for Index := 0 to DOMVendors.Count - 1 do
      begin
        CurrentDomVendor := DOMVendors.Vendors[Index];
        LogDomVendor(CurrentDomVendor);
        CurrentDomVendorDescription := CurrentDomVendor.Description;
        DomVendorComboBox.Items.Add(CurrentDomVendorDescription);
        if DefaultDOMVendor = CurrentDomVendorDescription then
          DefaultDomVendorIndex := DomVendorComboBox.Items.Count - 1;
      end;
      DomVendorComboBoxItemsCount := DomVendorComboBox.Items.Count;
      if (DefaultDomVendorIndex = NoSelection) then
      begin
        if DefaultDOMVendor = NullAsStringValue then
        begin
          if DomVendorComboBoxItemsCount > 0 then
            DefaultDomVendorIndex := 0;
        end
        else
          DefaultDomVendorIndex := DomVendorComboBoxItemsCount - 1;
      end;
      DomVendorComboBox.ItemIndex := DefaultDomVendorIndex;
    end;
    
    procedure TMainForm.LogDomVendor(const CurrentDomVendor: TDOMVendor);
    var
      CurrentDomVendorDescription: string;
      DocumentElement: IDOMElement;
      DomDocument: IDOMDocument; // xmldom.IDOMDocument is the plain XML DOM
      XmlDocument: IXMLDocument; // XMLIntf.IXMLDocument is the enrichted XML interface to the TComponent wrapper, which has a DOMDocument: IDOMDocument poperty, and allows obtaining XML from different sources (text, file, stream, etc)
      XmlDocumentInstance: TXMLDocument; // unit XMLDoc
    
      DOMNodeEx: IDOMNodeEx;
      XMLDOMDocument2: IXMLDOMDocument2;
    begin
      CurrentDomVendorDescription := CurrentDomVendor.Description;
      Logger.Log('DOMVendor', CurrentDomVendorDescription);
    
      XmlDocumentInstance := TXMLDocument.Create(nil);
      XmlDocumentInstance.DOMVendor := CurrentDomVendor;
      XmlDocument := XmlDocumentInstance;
    
      DomDocument := CurrentDomVendor.DOMImplementation.createDocument(NullAsStringValue, NullAsStringValue, nil);
    
      XmlDocument.DOMDocument := DomDocument;
      XmlDocument.LoadFromXML('');
      DomDocument := XmlDocument.DOMDocument; // we get another reference here, since we loaded some XML now
    
      DocumentElement := DomDocument.DocumentElement;
      if Assigned(DocumentElement) then
      begin
        DOMNodeEx := DocumentElement as IDOMNodeEx;
        Logger.Log(DOMNodeEx.xml);
      end;
    
      if IDomNodeHelper.GetXmlDomDocument2(DomDocument, XMLDOMDocument2) then
      begin
        // XSLPattern versus XPath
        // see https://stackoverflow.com/questions/784745/accessing-comments-in-xml-using-xpath
        // XSLPattern is 0 based, but XPath is 1 based.
        Logger.Log(IDomNodeHelper.SelectionLanguage, string(XMLDOMDocument2.getProperty(IDomNodeHelper.SelectionLanguage)));
        Logger.Log(IDomNodeHelper.SelectionNamespaces, string(XMLDOMDocument2.getProperty(IDomNodeHelper.SelectionNamespaces)));
      end;
    
    
      LogDomVendorFeatures(CurrentDomVendor,
        ['','1.0','2.0', '3.0'],
    //http://www.w3.org/TR/DOM-Level-3-Core/introduction.html#ID-Conformance
    //http://reference.sitepoint.com/javascript/DOMImplementation/hasFeature
    ['Core'
    ,'XML'
    ,'Events'
    ,'UIEvents'
    ,'MouseEvents'
    ,'TextEvents'
    ,'KeyboardEvents'
    ,'MutationEvents'
    ,'MutationNameEvents'
    ,'HTMLEvents'
    ,'LS'
    ,'LS-Async'
    ,'Validation'
    ,'XPath'
    ]);
    end;
    
    
    procedure TMainForm.LogDomVendorFeatures(const CurrentDomVendor: TDOMVendor; const Versions, Features: array of string);
    var
      AllVersions: string;
      Feature: string;
      Line: string;
      Supported: Boolean;
      SupportedAll: Boolean;
      SupportedNone: Boolean;
      SupportedVersions: IStringListWrapper;
      Version: string;
    begin
      SupportedVersions := TStringListWrapper.Create();
      for Version in Versions do
        AddSupportedVersion(Version, SupportedVersions);
      AllVersions := Format('All: %s', [SupportedVersions.CommaText]);
      for Feature in Features do
      begin
        SupportedAll := True;
        SupportedNone := True;
        SupportedVersions.Clear();
        for Version in Versions do
        begin
          Supported := CurrentDomVendor.DOMImplementation.hasFeature(Feature, Version);
          if Supported then
            AddSupportedVersion(Version, SupportedVersions);
          SupportedAll := SupportedAll and Supported;
          SupportedNone := SupportedNone and not Supported;
        end;
        if SupportedNone then
          Line := Format('None', [])
        else
        if SupportedAll then
          Line := Format('%s', [AllVersions])
        else
          Line := Format('%s', [SupportedVersions.CommaText]);
        Logger.Log('  ' + Feature, Line);
      end;
    end;
    

    Delphi XE will show these:

    DOMVendor:MSXML
    
    SelectionLanguage:XPath
    SelectionNamespaces:
      Core:None
      XML:Any,1.0
      Events:None
      UIEvents:None
      MouseEvents:None
      TextEvents:None
      KeyboardEvents:None
      MutationEvents:None
      MutationNameEvents:None
      HTMLEvents:None
      LS:None
      LS-Async:None
      Validation:None
      XPath:Any,1.0
    DOMVendor:ADOM XML v4
    ?
    
      Core:None
      XML:None
      Events:None
      UIEvents:None
      MouseEvents:None
      TextEvents:None
      KeyboardEvents:None
      MutationEvents:None
      MutationNameEvents:None
      HTMLEvents:None
      LS:None
      LS-Async:None
      Validation:None
      XPath:None
    

提交回复
热议问题