Jump to content
ertank

XML FindNode

Recommended Posts

Hello,

 

Using Delphi 10.2.3. I have attached xml file. I would like to find specific node (if it exists) in it and retrieve it's value.

 

My node existence check list is:

1- AdditionalDocumentReference (This is an optional node. Can be more than once in XML. I have to loop through all of them to be sure that node I am searching for exists or not. If no such node exists, searched node is certainly not exists)

2- DocumentType = XSLT (I am seaching DocumentType to be "XSLT". if current node is something else, I need to check other AdditionalDocumentReference nodes if there is any)

3- EmbeddedDocumentBinaryObject (I need Base64 encoded string of that node)

 

My current code is:

 

uses

  Xml.OmniXmlDom,   // <- this is for Omni XML (only available in XE7 and higher!)
  Xml.XmlDom,       // <- add this (important, otherwise the var DefaultDOMVendor isn’t available) Using "Omni XML" as default DOM provider
  Xml.XmlDoc,
  Xml.XmlIntf;


procedure DisplayInvoice(const Filename: string);
var
  Xml: IXmlDocument;
  ElementNode: IXMLNode;
  BaseNode: IXMLNode;
  ChildNode: IXMLNode;
  XSLTBase64: string;
begin
  if not TFile.Exists(Filename) then Exit();

  Xml := TXMLDocument.Create(Filename);
  ElementNode := Xml.ChildNodes.FindNode('Invoice');
  if ElementNode <> nil then
  begin
    BaseNode := ElementNode.ChildNodes.FindNode('cac:AdditionalDocumentReference', 'http://www.w3.org/2001/XMLSchema-instance');  // <--- here BaseNode returns nil
    if BaseNode <> nil then
    begin
      ChildNode := BaseNode.ChildNodes.FindNode('DocumentType');
      if ChildNode <> nil then
      begin
        if ChildNode.Text.ToUpper = 'XSLT' then
        begin
          ChildNode := BaseNode.ChildNodes.FindNode('Attachment');
          if ChildNode <> nil then
          begin
            ChildNode := ChildNode.ChildNodes.FindNode('EmbeddedDocumentBinaryObject');
            if ChildNode <> nil then
            begin
              XSLTBase64 := ChildNode.Text;
            end;
          end;
        end;
      end;
    end;
  end;
end;

Above code does not take into account multiple AdditionalDocumentReference as I failed to have a working code in the first place.

 

I have also tried not to use namespaces when using FindNode and that also failed.

 

Any help is appreciated.

 

Thanks & regards,

Ertan

 

ubl-tr.xml

Share this post


Link to post

Use a blank namespace for all subnodes.

BaseNode := ElementNode.ChildNodes.FindNode('AdditionalDocumentReference','');

 

Regards,

 

Ralf

 

 

Share this post


Link to post

I found how to use XML namespaces. Suggestion of @ergeka also works. It is possible to have same node name in different namespaces and that may result in a wrong node reading.

 

I needed to match namespace identifier in XMLNode and pass string of that identifier indicated at the beginning of xml file.

 

Thanks.

 

const
  cac = 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2';  // can be found at the beginning of XML
  cbc = 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2';  // can be found at the beginning of XML


function GetXSLTFromXML(const Filename: string): Boolean;
var
  Xml: IXmlDocument;
  ElementNode: IXMLNode;
  BaseNode: IXMLNode;
  ChildNode: IXMLNode;
  XSLTBase64: string;
  XSLTBytes: TBytes;
begin
  if not TFile.Exists(Filename) then Exit(False);

  Xml := TXMLDocument.Create(Filename);
  ElementNode := Xml.ChildNodes.FindNode('Invoice');
  if ElementNode <> nil then
  begin
    BaseNode := ElementNode.ChildNodes.FindNode('AdditionalDocumentReference', cac);
    while BaseNode <> nil do
    begin
      ChildNode := BaseNode.ChildNodes.FindNode('DocumentType', cbc);
      if ChildNode <> nil then
      begin
        if ChildNode.Text.ToUpper = 'XSLT' then
        begin
          ChildNode := BaseNode.ChildNodes.FindNode('Attachment', cac);
          if ChildNode <> nil then
          begin
            ChildNode := ChildNode.ChildNodes.FindNode('EmbeddedDocumentBinaryObject', cbc);
            if ChildNode <> nil then
            begin
              XSLTBase64 := ChildNode.Text;
              XSLTBytes := TNetEncoding.Base64.DecodeStringToBytes(XSLTBase64);
              TFile.WriteAllBytes(TPath.ChangeExtension(Filename, '.xslt'), XSLTBytes);
              Exit(True);
            end;
          end;
        end;
      end;
      BaseNode := BaseNode.NextSibling;
    end;
  end;

  Result := False;
end;


 

 

Edited by ertank

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×