Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

XML - Build, parse XML


  • Please log in to reply
45 replies to this topic
DigiDon
  • Members
  • 9 posts
  • Last active: Jan 10 2016 01:30 PM
  • Joined: 28 Feb 2014

Okay, I'm happy I found a working solution! :)

Thanks for putting me back on tracks ;)

 

EDIT:

Here a working solution to compare 2nd level nodes and 3rd level elements between two XML files and add them with values if they don't exist:

In this case it adds them along with the default text from the reference to the referee (I don't know if it is the right word but you got the idea)

 

I use it to check the language user-configurated XML against the default English language file of my program and add the default english text if they're missing. Thus if I update my program and they don't have the translated elements in their language file there will be no program errors and no missing text and it will be easy for them to spot and modify the missing elements.

 

PS : I used Coco's XML BUILDER Library of this topic : http://www.autohotke...uild-parse-xml/ and XConfig library indicated by Coco and that can be found here : https://github.com/c...oHotkey-XConfig

 

Adapt to your requirements and feel free to use for your language settings set up system, enjoy! ;)

    ;XMLLanguageFile ("" and "2") are XML user config language (of "XML_Language_Path" path variable) objects created by the 2 libraries
    XMLLanguageFile2 := new xml(XML_Language_Path)
    XMLLanguageFile2.transformXML()
    XMLLanguageFile2.saveXML()
    XMLLanguageFile := new XConfig(XML_Language_Path)

    ;XMLLanguageFile ("" and "2") are XML default English language file (of "XML_ENLanguage_Path" path variable) objects created by the 2 libraries
    XMLENLanguageFile2:=new xml(XML_ENLanguage_Path)
    XMLENLanguageFile:=new XConfig(XML_ENLanguage_Path)
    ;------------2nd level node--------------
    n:=XMLENLanguageFile2.SelectNodes("//*")
    while,Node:=n.item[A_Index-1]{
    NodeName:=Node.nodeName
    t := XMLLanguageFile.selectSingleNode("//" . NodeName)
    if !IsObject(t) ;If absent from the 2nd file
    {
    local AbsentNode=Node.nodeName
    msgbox %AbsentNode% Node is absent from your user XML language-file and so is added
    XMLLanguageFile.__Add("/ROOT", AbsentNode) ;we create it
    }
    ;---------3rd level nodes called elements-----------------
    e:=XMLENLanguageFile2.SelectNodes("/ROOT/" . NodeName . "/*")
    while,Element:=e.item[A_Index-1]{
    ElementName:=Element.nodeName
    NodeTextEn:=XMLENLanguageFile2.getText(Element)
    t := XMLLanguageFile.selectSingleNode("//" . NodeName . "/" . ElementName)
    if !IsObject(t) ;If absent from the 2nd file
    {
    local AbsentNode=Node.nodeName
    msgbox The element //%NodeName%/%ElementName% is absent from  your user XML language-file and so is added with default english text %NodeTextEn%
    XMLLanguageFile.__Add("//" . NodeName, "<" . ElementName . ">" . NodeTextEn . "</" . ElementName . ">")
    }
    }
    }
    XMLLanguageFile.__Save()
    XMLLanguageFile2 := new xml(XML_Language_Path)
    XMLLanguageFile2.transformXML()
    XMLLanguageFile2.saveXML()


maestrith
  • Members
  • 786 posts
  • Last active: Apr 11 2018 02:18 PM
  • Joined: 17 Sep 2005

I am glad that you were able to get it working :)


Please try out my scripts: AHK Studio Basic GUI Creator Menu Creator Donations


MJs
  • Members
  • 52 posts
  • Last active: Jan 15 2015 10:23 PM
  • Joined: 02 Mar 2014
#Include <xml>

try
    ; create an XMLDOMDocument object
    ; set its top-level node
    x := new xml("<root/>")
catch pe ; catch parsing error(if any)
    MsgBox, 16, PARSE ERROR
    , % "Exception thrown!!`n`nWhat: " pe.What "`nFile: " pe.File
    . "`nLine: " pe.Line "`nMessage: " pe.Message "`nExtra: " pe.Extra

; check if top-level node exists
; in this case, 'root'
if x.documentElement {
    ; add a 'comment' node
    x.addChild("root", "comment", "This is a comment")
    
    ; add an 'element' node to the 'root' node
    ; and set its 'nodeName' property to 'child'
    x.addElement("child", "root")
    
    ; add some child nodes
    for a, b in ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
        x.addElement("Element_" a, "//child", {attribute: "value " a}, b)
    
    ; Traverse and show 'attribute' and 'text' value
    ; of the newly appended nodes
    Loop, 7 {
        n := x.getChild("//child", "element", A_Index)
        MsgBox, % "Attribute: " n.getAttribute("attribute")
            . "`nText: " n.text
    }
    
    ; transform document using internal stylesheet
    x.transformXML()
    
    ; view XML document
    x.viewXML()
}

CAN'T GET THIS TO WORK AT ALL,

specifically methods that use "__Call" like addchild

    x.addChild("root", "comment", "This is a comment")

so, any idea why this is happening.

there is somethig with "__Call" that I can't see, or something else that I'm missing?



Jackie Sztuk _Blackholyman
  • Spam Officer
  • 3757 posts
  • Last active: Apr 03 2016 08:47 PM
  • Joined: 28 Feb 2012

can't say other then what version of AutoHotkay ar you using ?

 

msgbox % A_AhkVersion

 

if you what the most up to date version go here

 

Unfortunately, this domain continues to promote an outdated version of AutoHotkey. So most older users encouraged new users to migrate and participate at the new site ahkscript.org


Helping%20you%20learn%20autohotkey.jpg?d

[AHK] Version. 1.1+ [CLOUD] DropBox ; Copy [WEBSITE] Blog ; About

MJs
  • Members
  • 52 posts
  • Last active: Jan 15 2015 10:23 PM
  • Joined: 02 Mar 2014

thank you Blackholyman for your replay

if I were to guess I'd  say, it might be because I'm up to date, since the script is a year old

I couldn't figure out what was the error

I use the function directely:

x.addInsertE("addElement","node", "*", "this is a new node")

instead of calling addchild method.



docterry
  • Members
  • 2 posts
  • Last active: Jul 19 2014 12:24 AM
  • Joined: 20 Jan 2014

I am having difficulty trying to figure out how to move a node from one XML to another. I've read the other threads, but can't seem to make this work. It seems like such a simple task...

FileRead, source, SOURCE.XML
y := new XML(source)
---
<root>
    <id num="1">
        <parent>
            <child1>Text A</child1>
            <child2>Text B</child2>
            <child3>Text C</child3>
        </parent>
    <id num="2" />
    <id num="3" />
</root>

and

FileRead, dest, DEST.XML
z := new XML(dest)
---
<root>
    <id num="1" />
    <id num="2" />
    <id num="3" />
</root>

When I have tried

Loop, % (x := y.selectNodes("/root/id")).length {
	k := x.item((i:=A_Index)-1)
	    kNUM := k.getAttribute("num")
	    kPAR := k.selectSingleNode("parent")
	z.addChild("/root/id[@num='" kNUM "']", kPAR)
}

all I get is an error.

 

Is there a simple way to copy one node and paste it to another XML?

 

Thanks in advance!

 

 

UPDATE: Boy, do I feel silly. There really is a simple way to do this.

x := sourceXML.selectSingleNode("diagnoses").cloneNode(true)
y.appendChild(x)


Mapa4
  • Members
  • 10 posts
  • Last active: Aug 25 2017 06:42 PM
  • Joined: 11 Aug 2013

Hi,

 

I am trying to find a way to execute this XPath expression which purpose is to get the name of the root element after the 2 usual SOAP elements :

 

      local-name(/*[local-name()='Envelope']/*[local-name()='Body']/*[1])

 

It works well, returning "MyRoot", on a site like http://www.freeforma...ath-tester.html

with any SOAP envelope like this one :

 

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlso...oap/envelope/">
 <soapenv:Body>
    <MyRoot>
       <myFirstElement/>
    </MyRoot>
 </soapenv:Body>
</soapenv:Envelope>

 

I tried this Autohotkey code but it does not work :

 

xmlDoc := ComObjCreate("msxml2.DOMDocument.6.0")
xmlDoc.async := False
xmlDoc.load("z1.xml")
xmlDoc.SetProperty("SelectionLanguage", "XPath")
MsgBox % xmlDoc.selectSingleNode("local-name(/*[local-name()='Envelope']/*[local-name()='Body']/*[1])").text

 

And unfortunately, I found nothing in the Autohotkey forums approaching this problem.

 

Any help will be greatly appreciated.

 

<Mapa4/>



maestrith
  • Members
  • 786 posts
  • Last active: Apr 11 2018 02:18 PM
  • Joined: 17 Sep 2005
z1=
(
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlso...oap/envelope/">
<soapenv:Body>
<MyRoot>
<myFirstElement/>
</MyRoot>
</soapenv:Body>
</soapenv:Envelope>
)
;I tried this Autohotkey code but it does not work :
 
xmlDoc := ComObjCreate("msxml2.DOMDocument.6.0")
xmlDoc.SetProperty("SelectionLanguage","XPath")
xmlDoc.async := False
xmlDoc.loadxml(z1)
MsgBox % xmlDoc.selectSingleNode("//MyRoot").xml

Please try out my scripts: AHK Studio Basic GUI Creator Menu Creator Donations


Jackie Sztuk _Blackholyman
  • Spam Officer
  • 3757 posts
  • Last active: Apr 03 2016 08:47 PM
  • Joined: 28 Feb 2012
I don't have the time to test it out, but you may just need to set the namespace property

Example from another post: http://www.autohotke...post&pid=625747
Helping%20you%20learn%20autohotkey.jpg?d

[AHK] Version. 1.1+ [CLOUD] DropBox ; Copy [WEBSITE] Blog ; About

Mapa4
  • Members
  • 10 posts
  • Last active: Aug 25 2017 06:42 PM
  • Joined: 11 Aug 2013

Thanks Blackholyman, it was the key of my problem.



Ayy lmao
  • Members
  • 8 posts
  • Last active: Jan 01 2015 02:17 PM
  • Joined: 11 Nov 2014

Can someone provide an example on how to determine if a node has child nodes and how to iterate through these items?



Jackie Sztuk _Blackholyman
  • Spam Officer
  • 3757 posts
  • Last active: Apr 03 2016 08:47 PM
  • Joined: 28 Feb 2012
example:
xml = 
(
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <main>
        <parent>
            <child>childtext10</child>
            <child>childtext20</child>
        </parent>
        <parent>
            <child>childtext11</child>
            <child>childtext21</child>
        </parent>
    </main>
</root>
)


doc := ComObjCreate("MSXML2.DOMDocument.6.0")
doc.async := false
doc.loadXML(xml)
    
docNode := doc.selectSingleNode("//main/parent[2]")

if (docNode.childNodes.length > 0)
    for childnode in docNode.childNodes
        msgbox % childnode.text
return
Hope it helps
Helping%20you%20learn%20autohotkey.jpg?d

[AHK] Version. 1.1+ [CLOUD] DropBox ; Copy [WEBSITE] Blog ; About

Ayy lmao
  • Members
  • 8 posts
  • Last active: Jan 01 2015 02:17 PM
  • Joined: 11 Nov 2014

Thanks



DigiDon
  • Members
  • 9 posts
  • Last active: Jan 10 2016 01:30 PM
  • Joined: 28 Feb 2014

Hi Coco,

 

Hope you're fine.

 

I was wondering if we could move this thread to ahkscript.org forum? Meaning creating a new thread on ahkscript and linking to it in your original post?

 

I'm still using both of your XML classes for my software (to be released in a brand new version soon!) and I ran into some issues on newer Windows Versions that I would like to discuss.

 

I guess even if not a lot people are posting, there are still many that use XML for -among other- program configuration.

And there are not so many libraries/classes out there, yours are the only one worth it in my opinion ! :)

 

Anyway, I was testing my software in a newer 8.1 Windows (I'm staying with Windows 7) and I ran into a critical issue that made my software quite useless.

 

(Nom Inconnu means "Unknow Name" in French)

 

XML_Bug.jpg

 

This error was caused whenever I was trying to import an XML string into my XML file using XConfig class.

Everything is working good on my x64 Windows 7 computer though.

Windows 8.1 and 10 seem not to understand the call...

 

Specifically I am doing this kind of calls which cause the error:

NewXMLString=
(
<KnownPgrm Name="%CurrentPgrmName%">
<Class Name="%PClass%"></Class>
<Process Name="%PProcessName%"></Process>
</KnownPgrm>
)
XMLRecoDataFile.__Add("/ROOT", NewXMLString)

And this was of course

XMLRecoDataFile.__Add("/ROOT", NewXMLString)

which was causing the issue.

 

That made me really scared that all my software would have to go to a complete rewrite to be working on newer Windows because I was relying extensively on XML and quite often was I making these calls to be able to format very easily a whole XML block before inserting it.

 

Anyway, more fear than harm, I was able to work it out by replacing those calls by using your other XML_Builder class and creating each node at a time like this :

XMLRecoDataFile2.addElement("KnownPgrm", "/ROOT", {Name: CurrentPgrmName})
XMLRecoDataFile2.addElement("Class", "//KnownPgrm[@Name='" . CurrentPgrmName . "']", {Name: PClass})
XMLRecoDataFile2.addElement("Process", "//KnownPgrm[@Name='" . CurrentPgrmName . "']", {Name: PProcessName})

So I'm really relieved, but in the meantime I would like to know what is wrong with the previous calls..

(I posted to let other people know as well of course ;) )

 

I quite intensively researched the question but couldn't find anything useful as this "unknown name" error is very vague !

Does it has something to do that the OS is not in English?? (I just thought of that by writing this post but it seems very far-featched!)

 

I red that it may have someting to do with new internet explorer/Edge Security settings but I tried many things (disabling security options, runing as admin) to no avail so it doesn't seem to be the issue.

 

Do you or does someone has a clue?

Is there a working "reliable" way to insert a XML string block into an XML file in Windows 8.1 and 10 but which would work of course at least on 7 ?

 

By the way, I often ran into a second frequent issue: When I try to put XML that contains "&" characters with XConfig there is an error showing. I finally decided to make a stringreplace  when importing XML to convert them into "&amp;" as such:

EDIT : Not a good solution ! Read Below

	__XML2DOM(str) {
		static x

		if !x
			x := ComObjCreate(this.__MSXML())
			, x.async := false
		;Added by DigiDon : replace amperstand
		StringReplace, str, str, &, &amp;, All

At the time writing I wonder if the issue is similar in XML_Builder, I don't really know, probably no cause I just saw :

	toChar(ByRef str) {
		static e := [["<", "&lt;"], [">", "&gt;"], ["'", "&apos;"], ["""", "&quot;"], ["&", "&amp;"]]
		for a, b in e
		str := RegExReplace(str, b.2, b.1)
		return true
	}

Which seems to be a good solution that I will implement and that should be implemented in XConfig as it replaces other forbidden characters as < , >,  ', " as well ! :)

 

Edit: Solution was not good because __Add method allows to insert stings and so we can't replace these characters in strings that may contain Nodes (i.e. replace < by &lt; when the node is <Node>Substring</Node> would cause issues, and this is valid for other characters as well. I couldn't find a proper solution for now because I don't understand the coding of this class properly... :( Could Coco provide a solution? Or are we compelled to sanitize the sting everytime by ourselves before making the call? : Maybe this is the only solution if nodes can't be automatically properly recognized..

 

Thanks and cheers ! :)



production
  • Members
  • 4 posts
  • Last active: Dec 03 2015 07:22 PM
  • Joined: 19 Aug 2015

Trying to do the simplest of things but utterly defeated - save the XML to a file. I saw the link to https://msdn.microso...ibrary/ms753769which I gather means x.saveXML("test.xml") should work but I can't get it to.

 

I have: 

 

#Include <xml>
 
#SingleInstance,force
#NoEnv
SetWorkingDir %A_ScriptDir%
 
xmlPath := A_ScriptDir "\test.xml"
 
try
; create an XMLDOMDocument object
; set its top-level node
x := new xml("<root/>")
catch pe ; catch parsing error(if any)
MsgBox, 16, PARSE ERROR
, % "Exception thrown!!`n`nWhat: " pe.What "`nFile: " pe.File
. "`nLine: " pe.Line "`nMessage: " pe.Message "`nExtra: " pe.Extra
 
; check if top-level node exists
; in this case, 'root'
if x.documentElement {
; add a 'comment' node
x.addChild("root", "comment", "XML created by the test.ahk script")
 
; add an 'element' node to the 'root' node
; and set its 'nodeName' property to 'child'
x.addElement("child", "root", "Hello World")
 
; transform document using internal stylesheet
x.transformXML()
 
; save the XML
x.saveXML(xmlPath)
 
; view XML document
x.viewXML()
 
}
 
any pointers greatly appreciated.