XML/XPath: Difference between revisions
Line 50: | Line 50: | ||
</lang> |
</lang> |
||
{{libheader|AHK XPath}} |
{{libheader|AHK XPath}} |
||
With [http://www.autohotkey.com/forum/topic17549.html XPath library] by Titan |
|||
<lang AutoHotkey> |
<lang AutoHotkey> |
||
; http://www.autohotkey.com/forum/topic17549.html |
|||
#Include xpath.ahk |
#Include xpath.ahk |
||
Revision as of 00:51, 20 June 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Perform the following three XPath queries on the XML Document below:
- Retrieve the first "item" element
- Perform an action on each "price" element (print it out)
- Get an array of all the "name" elements
XML Document:
<inventory title="OmniCorp Store #45x10^3"><item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> <item upc="445322344" stock="18"> <name>Levitation Salve</name> <price>23.99</price> <description>Levitate yourself for up to 3 hours per application</description> </item> <item upc="485672034" stock="653"> <name>Blork and Freen Instameal</name> <price>4.95</price> <description>A tasty meal in a tablet; just add water</description> </item> <item upc="132957764" stock="44"> <name>Grob winglets</name> <price>3.56</price> <description>Tender winglets of Grob. Just add water</description> </item> </inventory>
AutoHotkey
With regular expressions <lang AutoHotkey> FileRead, inventory, xmlfile.xml
RegExMatch(inventory, "<item.*?</item>", item1) MsgBox % item1
pos = 1 While, pos := RegExMatch(inventory, "<price>(.*?)</price>", price, pos + 1)
MsgBox % price1
While, pos := RegExMatch(inventory, "<name>.*?</name>", name, pos + 1)
names .= name . "`n"
MsgBox % names </lang>
<lang AutoHotkey>
- Include xpath.ahk
xpath_load(doc, "xmlfile.xml")
- Retrieve the first "item" element
MsgBox % xpath(doc, "/inventory/section[1]/item[1]/text()")
- Perform an action on each "price" element (print it out)
prices := xpath(doc, "/inventory/section/item/price/text()") Loop, Parse, prices,`,
reordered .= A_LoopField "`n"
MsgBox % reordered
- Get an array of all the "name" elements
MsgBox % xpath(doc, "/inventory/section/item/name") </lang>
C#
<lang csharp> XmlReader XReader;
// Either read the xml from a string ... XReader = XmlReader.Create(new StringReader("<inventory title=... </inventory>")); // ... or read it from the file system. XReader = XmlReader.Create("xmlfile.xml"); // Create a XPathDocument object (which implements the IXPathNavigable interface) // which is optimized for XPath operation. (very fast). IXPathNavigable XDocument = new XPathDocument(XReader); // Create a Navigator to navigate through the document. XPathNavigator Nav = XDocument.CreateNavigator(); Nav = Nav.SelectSingleNode("//item"); // Move to the first element of the selection. (if available). if(Nav.MoveToFirst()) { Console.WriteLine(Nav.OuterXml); // The outer xml of the first item element. } // Get an iterator to loop over multiple selected nodes. XPathNodeIterator Iterator = XDocument.CreateNavigator().Select("//price"); while (Iterator.MoveNext()) { Console.WriteLine(Iterator.Current.Value); } Iterator = XDocument.CreateNavigator().Select("//name"); // Use a generic list. List<string> NodesValues = new List<string>(); while (Iterator.MoveNext()) { NodesValues.Add(Iterator.Current.Value); } // Convert the generic list to an array and output the count of items. Console.WriteLine(NodesValues.ToArray().Length);</lang>
ColdFusion
<cfsavecontent variable="xmlString"> <inventory ... </inventory> </cfsavecontent> <cfset xml = xmlParse(xmlString)> <!--- First Task ---> <cfset itemSearch = xmlSearch(xml, "//item")> <!--- item = the first Item (xml element object) ---> <cfset item = itemSearch[1]> <!--- Second Task ---> <cfset priceSearch = xmlSearch(xml, "//price")> <!--- loop and print each price ---> <cfloop from="1" to="#arrayLen(priceSearch)#" index="i"> #priceSearch[i].xmlText#<br/> </cfloop> <!--- Third Task ---> <!--- array of all the name elements ---> <cfset names = xmlSearch(xml, "//name")> <!--- visualize the results ---> <cfdump var="#variables#">
Groovy
<lang groovy>def inventory = new XmlSlurper().parseText("<inventory...") //optionally parseText(new File("inv.xml").text) def firstItem = inventory.section.item[0] //1. first item inventory.section.item.price.each { println it } //2. print each price def allNamesArray = inventory.section.item.name.collect {it} //3. collect item names into an array</lang>
JavaScript
<lang javascript> //create XMLDocument object from file
var xhr = new XMLHttpRequest(); xhr.open('GET', 'file.xml', false); xhr.send(null); var doc = xhr.responseXML; //get first <item> element var firstItem = doc.evaluate( '//item[1]', doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; alert( firstItem.textContent ); //output contents of <price> elements var prices = doc.evaluate( '//price', doc, null, XPathResult.ANY_TYPE, null ); for( var price = prices.iterateNext(); price != null; price = prices.iterateNext() ) { alert( price.textContent ); } //add <name> elements to array var names = doc.evaluate( '//name', doc, null, XPathResult.ANY_TYPE, null); var namesArray = []; for( var name = names.iterateNext(); name != null; name = names.iterateNext() ) { namesArray.push( name ); } alert( namesArray );</lang>
Although some browsers support XPath, working with XML is much easier with E4X.
<lang javascript> //create XML object from file
var xhr = new XMLHttpRequest(); xhr.open('GET', 'file.xml', false); xhr.send(null); var doc = new XML(xhr.responseText); //get first <item> element var firstItem = doc..item[0]; alert( firstItem ); //output contents of <price> elements for each( var price in doc..price ) { alert( price ); } //add <name> elements to array var names = []; for each( var name in doc..name ) { names.push( name ); } alert( names );</lang>
Perl
<lang perl> use XML::XPath qw();
my $x = XML::XPath->new('<inventory ... </inventory>'); [$x->findnodes('//item[1]')->get_nodelist]->[0]; print $x->findnodes_as_string('//price'); $x->findnodes('//name')->get_nodelist;</lang>
PHP
<lang php>
<?php //PHP5 only example due to changes in XML extensions between version 4 and 5 (Tested on PHP5.2.0) $doc = DOMDocument::loadXML('<inventory title="OmniCorp Store #45x10^3">...</inventory>'); //Load from file instead with $doc = DOMDocument::load('filename'); $xpath = new DOMXPath($doc); /* 1st Task: Retrieve the first "item" element */ $nodelist = $xpath->query('//item'); $result = $nodelist->item(0); /* 2nd task: Perform an action on each "price" element (print it out) */ $nodelist = $xpath->query('//price'); for($i = 0; $i < $nodelist->length; $i++) { //print each price element in the DOMNodeList instance, $nodelist, as text/xml followed by a newline print $doc->saveXML($nodelist->item($i))."\n"; } /* 3rd Task: Get an array of all the "name" elements */ $nodelist = $xpath->query('//name'); //our array to hold all the name elements, though in practice you'd probably not need to do this and simply use the DOMNodeList $result = array(); //a different way of iterating through the DOMNodeList foreach($nodelist as $node) { $result[] = $node; }
</lang>
Python
<lang python>
- Python has basic xml parsing built in
from xml.dom import minidom
xmlfile = file("test3.xml") # load xml document from file xmldoc = xmldom.parse(xmlfile).documentElement # parse from file stream or... xmldoc = xmldom.parseString("<inventory title="OmniCorp Store #45x10^3">...</inventory>").documentElement # alternatively, parse a string
- 1st Task: Retrieve the first "item" element
i = xmldoc.getElementsByTagName("item") # get a list of all "item" tags firstItemElement = i[0] # get the first element
- 2nd task: Perform an action on each "price" element (print it out)
for j in xmldoc.getElementsByTagName("price"): # get a list of all "price" tags print j.childNodes[0].data # XML Element . TextNode . data of textnode
- 3rd Task: Get an array of all the "name" elements
namesArray = xmldoc.getElementsByTagName("name") </lang>
Ruby
<lang ruby> #Example taken from the REXML tutorial (http://www.germane-software.com/software/rexml/docs/tutorial.html)
require "rexml/document" include REXML #create the REXML Document from the string (%q is Ruby's multiline string, everything between the two @-characters is the string) doc = Document.new( %q@<inventory title="OmniCorp Store #45x10^3"> ... </inventory> @ ) # The invisibility cream is the first <item> invisibility = XPath.first( doc, "//item" ) # Prints out all of the prices XPath.each( doc, "//price") { |element| puts element.text } # Gets an array of all of the "name" elements in the document. names = XPath.match( doc, "//name" )</lang>
Tcl
<lang tcl># assume $xml holds the XML data package require tdom set doc [dom parse $xml] set root [$doc documentElement]
set allNames [$root selectNodes //name] puts [llength $allNames] ;# ==> 4
set firstItem [lindex [$root selectNodes //item] 0] puts [$firstItem @upc] ;# ==> 123456789
foreach node [$root selectNodes //price] {
puts [$node text]
}</lang>
Visual Basic .NET
Dim first_item = xml.XPathSelectElement("//item") Console.WriteLine(first_item) For Each price In xml.XPathSelectElements("//price") Console.WriteLine(price.Value) Next Dim names = (From item In xml.XPathSelectElements("//name") Select item.Value).ToArray
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" /> <xsl:template match="/"> <!-- 1. first item element --> <xsl:text> The first item element is</xsl:text> <xsl:value-of select="//item[1]" /> <!-- 2. Print each price element --> <xsl:text> The prices are: </xsl:text> <xsl:for-each select="//price"> <xsl:text> </xsl:text> <xsl:copy-of select="." /> </xsl:for-each> <!-- 3. Collect all the name elements --> <xsl:text> The names are: </xsl:text> <xsl:copy-of select="//name" /> </xsl:template> </xsl:stylesheet>