ertank 28 Posted October 27, 2018 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
ergeka 5 Posted October 28, 2018 Use a blank namespace for all subnodes. BaseNode := ElementNode.ChildNodes.FindNode('AdditionalDocumentReference',''); Regards, Ralf Share this post Link to post
ertank 28 Posted October 29, 2018 (edited) 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 October 29, 2018 by ertank Share this post Link to post