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
Coco
  • Members
  • 697 posts
  • Last active: Oct 31 2015 07:26 PM
  • Joined: 27 Jul 2012

<XML />

 

 
I find myself using XML a lot(storage, IPC, etc.) and I needed a wrapper that would simplify some stuff, thus, this. 
 
SOME FUNCTIONALITY:
- Access XML DOM Properties/Methods directly as well as some custom class methods using the object derived from the class.
  (An exception is thrown in case of error)
- For debugging, you can use the viewXML() method to view your current document in "Pretty Print".
- Alternate way to call selectSingleNode the short-hand way(for those who are lazy to type)
    xmlDoc[XPath] normally it would be something like xmlDoc.selectSingleNode(XPath)  (you can do it both ways icon_razz.gif )
- I've implemented some methods that I think would simplify some common stuff when working with XML
 
MSDN Links:
XML DOM
XML DOM Properties
XML DOM Methods
 
Thanks to:
maestrith - I borrowed some code from his XML wrapper(http://www.autohotke...010-xml-parser/)
 
**DOCUMENTATION IS WITHIN THE CODE**
 

CODE : 

Spoiler


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

Here's some sample code:

#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()
}

Another sample

#Include <xml>

doc =
(LTrim
<root name="XML Sample">
	<!-- A comment -->
	<child attribute="value">
		<![CDATA[This is a CDATA Section]]>
		This is a text
		<subchild_1>Text</subchild_1>
		<subchild>
			Another text
			<node>The quick brown fox jumps over tha lazy dog</node>
		</subchild>
		Second text
	</child>
	<child>
		Some text
		<subchild name="Hello World">AutoHotkey</subchild>
		<!-- Another comment -->
	</child>
</root>
)


try
	; create an XMLDOMDocument object
	; and load the XML string
	x := new xml(doc)
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
	
if x.documentElement {
	; class Built-in methods
	MsgBox, % x.getText("//node") ; getText() method
	MsgBox, % x.getAtt("//child[2]/subchild", "name") ; getAtt() method
	
	; XML DOM methods (counter-part)
	n := x.selectSingleNode("//node")
	MsgBox, % n.text ; get text
	
	; Alternate way of calling 'selectSingleNode'
	n := x["//child[2]/subchild"]
	MsgBox, % n.getAttribute("name") ; get attribute
	
	x.transformXML()
	x.viewXML()
}

ExitApp


R3gX
  • Members
  • 307 posts
  • Last active: Dec 29 2013 04:50 PM
  • Joined: 28 Feb 2011
The code looks promising!
I'm gonna play with it tomorrow.
 
(It's a pity that nobody leave a reply!)

signature.png
Previously known as TomXIII
AutoHotkey version : 1.1.10


m3nth0l
  • Members
  • 27 posts
  • Last active: Feb 13 2015 11:34 PM
  • Joined: 19 Oct 2011

Very slick! Thanks for this.



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

Thanks guys! wink.png

 

UPDATES

- Removed some duplicate code. (Consolidated methods that are using similar routines)

- Modified the viewXML function

    It no longer uses DynaRun, thus no other process is created. 

    Implemenetd two types of viewing, default is 'Pretty Print'(XML is viewed in embedded IE control). The other is plain text(Edit control)

    Usage:

xmlObj.viewXML() ; Default , 'Pretty Print'
xmlObj.viewXML(false) ; Plain text

- Fixed documentation indentation/alignment. Changed from tab to spaces. (it should align properly now on any text editor)

- Some minor fixes



DarkM
  • Members
  • 72 posts
  • Last active: Nov 13 2013 09:54 PM
  • Joined: 22 Sep 2010

getting error when trying to run my script with this include.

 

Line #: 111

Line Text: class xml

Error: line does not contain a recognized action 



fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

getting error when trying to run my script with this include.

You're using an outdated version of AutoHotkey (very likely v1.0.48.05). Please upgrade to the latest (v1.1.09.03 at the time of writing) unless you have a specific reason not to.
Hope this helps.

DarkM
  • Members
  • 72 posts
  • Last active: Nov 13 2013 09:54 PM
  • Joined: 22 Sep 2010

You're using an outdated version of AutoHotkey (very likely v1.0.48.05). Please upgrade to the latest (v1.1.09.03 at the time of writing) unless you have a specific reason not to.
Hope this helps.

Thanks for the quick response :)



DarkM
  • Members
  • 72 posts
  • Last active: Nov 13 2013 09:54 PM
  • Joined: 22 Sep 2010

Another quick question. How do I save, and read the xml? Don't see any documentation for that.

 

x.saveXML(directory) doesnt work.



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

Another quick question. How do I save, and read the xml? Don't see any documentation for that.
 
x.saveXML(directory) doesnt work.

 

x.save(directory)   see http://msdn.microsof...ibrary/ms753769
x.loadXML(xmlString)  see http://msdn.microsof...ibrary/ms754585
x.load(xmlSource)  see http://msdn.microsof...ibrary/ms762722



DarkM
  • Members
  • 72 posts
  • Last active: Nov 13 2013 09:54 PM
  • Joined: 22 Sep 2010

x.save(directory)   see http://msdn.microsof...ibrary/ms753769
x.loadXML(xmlString)  see http://msdn.microsof...ibrary/ms754585
x.load(xmlSource)  see http://msdn.microsof...ibrary/ms762722

Ah thanks so for load, instead of x := new xml(blabla)  it would be x := new load(blabla)?

 

EDIT: Tried it and it works. Thanks happy.png

 

Heh. I am a noob. Now how do I start working with it? x.viewXML() doesn't even work after doing x:= new load(xml loc)



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

Ah thanks so for load, instead of x := new xml(blabla)  it would be x := new load(blabla)?

 

EDIT: Tried it and it works. Thanks happy.png

 

Heh. I am a noob. Now how do I start working with it? x.viewXML() doesn't even work after doing x:= new load(xml loc)

x := new xml(xmlStringorFile)
x.viewXML()

 

OR

x := new xml() ; blank in this case
x.load(xmlSource) ; or x.loadXML(xmlString)
x.viewXML()


DarkM
  • Members
  • 72 posts
  • Last active: Nov 13 2013 09:54 PM
  • Joined: 22 Sep 2010

Ah danke.



Sidola
  • Members
  • 76 posts
  • Last active: Apr 07 2015 08:34 AM
  • Joined: 20 Jun 2012

Hi, I'm having problems figuring out how to grab all the children of a node to then get their contents.

<root>
	<child>
		<Element_1>Sunday</Element_1> 
		<Element_2>Monday</Element_2> 
		<Element_3>Tuesday</Element_3> 
		<Element_4>Wednesday</Element_4> 
		<Element_5>Thursday</Element_5> 
		<Element_6>Friday</Element_6> 
		<Element_7>Saturday</Element_7> 
	</child>
</root>

How would I use the getChildren function to grab all the children of "child" and then get their contents dynamically?

 

I think I understand it far enough that the getChildren function returns an object with all the children, but I have no clue how to work with that object in order to extract the contents of each child...

 

Edit:

So, this works...

ns := x.getChildren("//child", "element")
Loop % ns._MaxIndex() 
{
	n := x.getChild("//child", "element", A_Index)
	MsgBox, % "Attribute: " n.getAttribute("attribute")
		. "`nText: " n.text
}

But I'm guessing there's a smoother way to make it work? Also, it's there a way to only grab children with a specific name?

 

Edit2:

And another method.

ns := x.getChildren("//child", "element")

for each, value in ns {
	msgBox % x.getText(value)
}

Still no luck with figuring out how to work with the node-names inside the ns-object.



Coco
  • Members
  • 697 posts
  • Last active: Oct 31 2015 07:26 PM
  • Joined: 27 Jul 2012
#Include <xml>

src =
(
<root>
	<child>
		<Element_1>Sunday</Element_1> 
		<Element_2>Monday</Element_2> 
		<Element_3>Tuesday</Element_3> 
		<Element_4>Wednesday</Element_4> 
		<Element_5>Thursday</Element_5> 
		<Element_6>Friday</Element_6> 
		<Element_7>Saturday</Element_7> 
	</child>
</root>
)

x := new xml(src)
c := x.getChild(x.root)
e := c.selectSingleNode("Element_5")
MsgBox, % "nodeName == " e.nodeName
        . "`ntext == " e.text " or " x.getText(e)
ExitApp

I have yet to update this with my recent version which supports regex when retrieving attributes and elements by name. This is useful when working dynamically as XML is case-sensitive.