Jump to content

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

XML Parser


  • Please log in to reply
16 replies to this topic
maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005
I wrote this script to make an easy way to interact with XML files.
All of the features should be explained in the code.
If I did not explain something clearly let me know.
There is an amazing amount of information Here if you want to learn more about xpath or xml files in general.

#SingleInstance, Force
gui:=new xml("gui","Wierd","acid.xml") 		;Creates an xml with the filename of acid.xml, a root node of Wierd, and an association named gui.
another:=new xml("another")				;Creates an xml with the filename of another.xml, a root node of another, and an association named another.
gui.add("Just_A_Path")					;Add Just_A_Path to the gui xml
gui.add("Path","","With text")				;Add a path named 'Path' with text 'With text' to the gui xml
gui.add("unique",{value:3},"",1)			;Add a path named 'unique' with the attribute 'value' and the value of '3' to the gui xml
gui.add("unique",{value:3},"",1)			;Add a duplicate of the above
gui.add("unique",{value:4},"","",{value:3})	;Re-assign '4' to the attribute 'value'
for a,b in {gui:gui,another:another}{			
	b.add("foo",{this:1})				
	b.add("foo/bar/another",{this:1},"Hi")		
	b.add("foo/bar",{another:1})			
	b.add("foo",{that:1},"Hello",1)			
}
m(gui[],another[])					;Displays the xml files.
gui.transform()						;Transforms them from a file without indentations to a file with them.
another.transform()
p:=gui.sn("//*")					;Selects all of the nodes in the gui xml.
while,v:=p.item[A_Index-1]				;Loops all of the nodes that were selected in the line before
m(v.xml)						;Displays the node in the current loop
m(gui.ssn("//*[text()='Hi']").xml)			;Finds the node that contains the text value of Hi (Case sensitive)
m(gui[],another[])					;Displaying the xml files after the transform.
gui.save()						;Save the gui file
another.save()						;Save the another file
return
class xml{
	__New(param*){
		ref:=param.1,root:=param.2,file:=param.3
		file:=file?file:ref ".xml",root:=!root?ref:root
		temp:=ComObjCreate("MSXML2.DOMDocument"),temp.setProperty("SelectionLanguage","XPath")
		ifexist %file%
		temp.load(file),this.xml:=temp
		else
		this.xml:=xml.CreateElement(temp,root)
		this.file:=file
		xml.list({ref:ref,xml:this.xml,obj:this})
	}
	__Get(){
		return this.xml.xml
	}
	CreateElement(doc,root){
		x:=doc.CreateElement(root),doc.AppendChild(x)
		return doc
	}
	add(path,att="",text="",dup="",find=""){
		main:=this.xml.SelectSingleNode("*")
		for a,b in find
		if found:=main.SelectSingleNode("//" path "[@" a "='" b "']"){
			for a,b in att
			found.setattribute(a,b)
			return found
		}
		if p:=this.xml.SelectSingleNode(path)
		for a,b in att
		p.SetAttribute(a,b)
		else
		{
			p:=main
			Loop,Parse,path,/
			{
				total.=A_LoopField "/"
				if dup
				new:=this.xml.CreateElement(A_LoopField),p.AppendChild(new)
				else if !new:=p.SelectSingleNode("//" Trim(total,"/"))
				new:=this.xml.CreateElement(A_LoopField),p.AppendChild(new)
				p:=new
			}
			for a,b in att
			p.SetAttribute(a,b)
			if Text
			p.text:=text
		}
	}
	remove(){
		this.xml:=""
	}
	save(){
		this.xml.save(this.file)
	}
	transform(){
		this.xml.transformNodeToObject(xml.style(),this.xml)
	}
	ssn(node){
		return this.xml.SelectSingleNode(node)
	}
	sn(node){
		return this.xml.SelectNodes(node)
	}
	style(){
		static
		if !IsObject(xsl){
			xsl:=ComObjCreate("MSXML2.DOMDocument")
			style=
			(
			<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
			<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
			<xsl:template match="@*|node()">
			<xsl:copy>
			<xsl:apply-templates select="@*|node()"/>
			<xsl:for-each select="@*">
			<xsl:text></xsl:text>
			</xsl:for-each>
			</xsl:copy>
			</xsl:template>
			</xsl:stylesheet>
			)
			xsl.loadXML(style), style:=null
		}
		return xsl
	}
}
m(x*){
	for a,b in x
	list.=b "`n"
	MsgBox,% list
}


Coco
  • Members
  • 697 posts
  • Last active: Oct 31 2015 07:26 PM
  • Joined: 27 Jul 2012
Nice!! Class :D

maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005

Nice!! Class :D

Thank you ;)

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Looks great! I'm at work so can't play with it, but I've come into a need for something like this a few times. Thanks!

3nL8f.png


maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005

Looks great! I'm at work so can't play with it, but I've come into a need for something like this a few times. Thanks!

No problem :) I really like your signature image! How did you make that?

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Thanks. :). Just put it together really quick in Photoshop. :p.

3nL8f.png


maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005
I made a small error.
temp:=ComObjCreate("MSXML2.DOMDocument"),doc.setProperty("SelectionLanguage","XPath")
Should be
temp:=ComObjCreate("MSXML2.DOMDocument"),temp.setProperty("SelectionLanguage","XPath")
Doc in the first code is not an actual xml object. The original post is updated. Sorry about that.
I was working on
lastsyntax:=ssn(ssn(com,".."),"syntax[contains(text(),'" kw[find] "')]/@syntax").text
and I kept getting an error that "contains(" was not a valid xpath command. After 30 minutes I finally noticed that the .setproperty value was being applied to nothing. :)

Albireo
  • Members
  • 558 posts
  • Last active: Dec 13 2019 02:02 PM
  • Joined: 01 Feb 2006
Hello!
When I try to run the script below (above). I got an error

Error at line 6
Line text: {value
Error: The leftmost character above is illegal in an expression.
The program will exit.

The program code
#SingleInstance, Force
gui:=new xml("gui","Wierd","acid.xml") ; Creates an xml with the filename of acid.xml, a root node of Wierd, and an association named gui.
another:=new xml("another")	 ; Creates an xml with the filename of another.xml, a root node of another, and an association named another.
gui.add("Just_A_Path")	 ; Add Just_A_Path to the gui xml
gui.add("Path","","With text") ; Add a path named 'Path' with text 'With text' to the gui xml
gui.add("Unique",{value:3},"",1) ; Add a path named 'unique' with the attribute 'value' and the value of '3' to the gui xml
gui.add("unique",{value:3},"",1) ; Add a duplicate of the above
gui.add("unique",{value:4},"","",{value:3}) ; Re-assign '4' to the attribute 'value'
for a,b in {gui:gui,another:another}{
b.add("foo",{this:1})
b.add("foo/bar/another",{this:1},"Hi")
b.add("foo/bar",{another:1})
b.add("foo",{that:1},"Hello",1)
}
m(gui[],another[])	 ;Displays the xml files.
gui.transform()	 ;Transforms them from a file without indentations to a file with them.
another.transform()
p:=gui.sn("//*")	 ;Selects all of the nodes in the gui xml.
while,v:=p.item[A_Index-1] ;Loops all of the nodes that were selected in the line before
m(v.xml)	 ;Displays the node in the current loop
m(gui.ssn("//*[text()='Hi']").xml) ;Finds the node that contains the text value of Hi (Case sensitive)
m(gui[],another[])	 ;Displaying the xml files after the transform.
gui.save()	 ;Save the gui file
another.save()	 ;Save the another file
return
class xml{
__New(param*){
ref:=param.1,root:=param.2,file:=param.3
file:=file?file:ref ".xml",root:=!root?ref:root
temp:=ComObjCreate("MSXML2.DOMDocument"),temp.setProperty("SelectionLanguage","XPath")
ifexist %file%
temp.load(file),this.xml:=temp
else
this.xml:=xml.CreateElement(temp,root)
this.file:=file
xml.list({ref:ref,xml:this.xml,obj:this})
}
__Get(){
return this.xml.xml
}
CreateElement(doc,root){
x:=doc.CreateElement(root),doc.AppendChild(x)
return doc
}
add(path,att="",text="",dup="",find=""){
main:=this.xml.SelectSingleNode("*")
for a,b in find
if found:=main.SelectSingleNode("//" path "[@" a "='" b "']"){
for a,b in att
found.setattribute(a,<img src='http://cdn.autohotkey.com/board//public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />
return found
}
if p:=this.xml.SelectSingleNode(path)
for a,b in att
p.SetAttribute(a,<img src='http://cdn.autohotkey.com/board//public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />
else
{
p:=main
Loop,Parse,path,/
{
total.=A_LoopField "/"
if dup
new:=this.xml.CreateElement(A_LoopField),p.AppendChild(new)
else if !new:=p.SelectSingleNode("//" Trim(total,"/"))
new:=this.xml.CreateElement(A_LoopField),p.AppendChild(new)
p:=new
}
for a,b in att
p.SetAttribute(a,<img src='http://cdn.autohotkey.com/board//public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />
if Text
p.text:=text
}
}
remove(){
this.xml:=""
}
save(){
this.xml.save(this.file)
}
transform(){
this.xml.transformNodeToObject(xml.style(),this.xml)
}
ssn(node){
return this.xml.SelectSingleNode(node)
}
sn(node){
return this.xml.SelectNodes(node)
}
style(){
static
if !IsObject(xsl){
xsl:=ComObjCreate("MSXML2.DOMDocument")
style=
(
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:for-each select="@*">
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
)
xsl.loadXML(style), style:=null
}
return xsl
}
}
m(x*){
for a,b in x
list.=b "`n"
MsgBox,% list
}

Have I missed something?

//Jan

maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005
I ran your script on my PC and it ran perfectly. A quick question, what version of AHK are you running? Try to update to the most recent version (AHK_L is required) so the main download should work. If that does not fix the problem let me know.

hoppfrosch
  • Members
  • 399 posts
  • Last active: Feb 26 2016 05:31 AM
  • Joined: 25 Jan 2006

Question: I have a XML-file, containing a lot of nodes with same nodenames which can be distinguished by different attribute values.

 

<node att="A"></node>
<node att="B"></node>
<node att="C"></node>

This is already stored within a file. After reading the file correctly, I want to extend my XML contents.

How can I add a child to node with att="B"? Result should be:

<node att="B"><child childatt="value">Hi!</child></node>

What I tried (using XPath syntax):

 

xpath := "node[@att ='B']/child"
Myxml.add(xpath,{childatt:"value"},"HI!",1)

 

I tried other variants as well, without success ...

 

Any help welcome ...



maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005

Question: I have a XML-file, containing a lot of nodes with same nodenames which can be distinguished by different attribute values.

 

<node att="A"></node>
<node att="B"></node>
<node att="C"></node>

This is already stored within a file. After reading the file correctly, I want to extend my XML contents.

How can I add a child to node with att="B"? Result should be:

<node att="B"><child childatt="value">Hi!</child></node>

What I tried (using XPath syntax):

 

xpath := "node[@att ='B']/child"
Myxml.add(xpath,{childatt:"value"},"HI!",1)

 

I tried other variants as well, without success ...

 

Any help welcome ...

Give this a shot.

gui:=new xml("gui")

for a,b in ["A","B","C"]
Gui.Add("node",{att:b},"",1)
Gui.Transform()
Gui.Add("node[@att='B']",{childatt:"value"},"Hi!")
MsgBox % gui[]
oops...i just realized you created a child...give me a sec.


maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005
gui:=new xml("gui")
for a,b in ["A","B","C"]
Gui.Add("node",{att:b},"",1)
Gui.Transform()
Gui.Add("node[@att='B']/child",{childatt:"value"},"Hi!")
MsgBox % gui[]
xml.JPG
What you did is exactly right as far as the xpath goes.  I hope that you get it figured out.  If you like send me a copy of the xml and I will see if I can add to it.
I ran into the same error when using the "dup" value.  Try to take that off and it should work
 
Gui.Add("node[@att='B']/child",{childatt:"value"},"Hi!",1)
should be
Gui.Add("node[@att='B']/child",{childatt:"value"},"Hi!")
 
I have no idea why, but it does not work with the duplicate.


naroyya978
  • Members
  • 26 posts
  • Last active: Nov 04 2013 05:13 PM
  • Joined: 28 Dec 2012

Hi There,

 

Can any one help me out to pase an XML and get the data.

 

I want to parse the below xml and get the node values, 

 

<tns:ShippingDocumentationNotification><ssdh:DocumentHeader><ssdh:DocumentInformation><ssdh:Creation>2013-01-22T22:37:09-08:00</ssdh:Creation><ssdh:DocumentIdentification><ssdh:Identifier>400007547</ssdh:Identifier><ssdh:Type>PICK RELEASE</ssdh:Type><ssdh:StandardDocumentIdentification><ssdh:Standard>RosettaNet</ssdh:Standard><ssdh:Version>R12-3B18</ssdh:Version></ssdh:StandardDocumentIdentification></ssdh:DocumentIdentification></ssdh:DocumentInformation></ssdh:DocumentHeader>

</tns:ShippingDocumentationNotification>

 

When I am trying to parse using Java, i am getting this error " The prefix "tns" for element "tns:ShippingDocumentationNotification" is not bound. "Is there any script to do this..?

 

thanks in adv.



maestrith
  • Members
  • 786 posts
  • Last active: Apr 10 2019 01:28 PM
  • Joined: 17 Sep 2005

Hi There,

 

Can any one help me out to pase an XML and get the data.

 

I want to parse the below xml and get the node values, 

 

<tns:ShippingDocumentationNotification><ssdh:DocumentHeader><ssdh:DocumentInformation><ssdh:Creation>2013-01-22T22:37:09-08:00</ssdh:Creation><ssdh:DocumentIdentification><ssdh:Identifier>400007547</ssdh:Identifier><ssdh:Type>PICK RELEASE</ssdh:Type><ssdh:StandardDocumentIdentification><ssdh:Standard>RosettaNet</ssdh:Standard><ssdh:Version>R12-3B18</ssdh:Version></ssdh:StandardDocumentIdentification></ssdh:DocumentIdentification></ssdh:DocumentInformation></ssdh:DocumentHeader>

</tns:ShippingDocumentationNotification>

 

When I am trying to parse using Java, i am getting this error " The prefix "tns" for element "tns:ShippingDocumentationNotification" is not bound. "Is there any script to do this..?

 

thanks in adv.

I can not get it to load, and I am not too terribly good with xml files with ":" in the elements. What data are you looking for?



Coco
  • Members
  • 697 posts
  • Last active: Oct 31 2015 07:26 PM
  • Joined: 27 Jul 2012

@naroyya978: It seems that you would need to declare namespaces. Use the setProperty()  method and set the SelectionNamespaces(Second level DOM property) property.

doc.setProperty("SelectionNamespaces", "xmlns:tns='http://www.foo.com' xmlns:ssdh='http://www.bar.com'")