XML/XPath: Difference between revisions
(added Haskell (without using specialized modules)) |
(Added FreeBASIC) |
||
(121 intermediate revisions by 60 users not shown) | |||
Line 2: | Line 2: | ||
Perform the following three XPath queries on the XML Document below: |
Perform the following three XPath queries on the XML Document below: |
||
* Retrieve the first "item" element |
* '''//item[1]''': Retrieve the first "item" element |
||
* Perform an action on each "price" element (print it out) |
* '''//price/text()''': Perform an action on each "price" element (print it out) |
||
* Get an array of all the "name" elements |
* '''//name''': Get an array of all the "name" elements |
||
XML Document: |
XML Document: |
||
Line 33: | Line 33: | ||
</section> |
</section> |
||
</inventory> |
</inventory> |
||
=={{header|AArch64 Assembly}}== |
|||
{{works with|as|Raspberry Pi 3B version Buster 64 bits}} |
|||
<syntaxhighlight lang="aarch64 assembly"> |
|||
/* ARM assembly AARCH64 Raspberry PI 3B */ |
|||
/* program xpathXml64.s */ |
|||
/*******************************************/ |
|||
/* Constantes file */ |
|||
/*******************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeConstantesARM64.inc" |
|||
.equ NBMAXELEMENTS, 100 |
|||
/*******************************************/ |
|||
/* Structures */ |
|||
/********************************************/ |
|||
/* structure xmlNode*/ |
|||
.struct 0 |
|||
xmlNode_private: // application data |
|||
.struct xmlNode_private + 8 |
|||
xmlNode_type: // type number, must be second ! |
|||
.struct xmlNode_type + 8 |
|||
xmlNode_name: // the name of the node, or the entity |
|||
.struct xmlNode_name + 8 |
|||
xmlNode_children: // parent->childs link |
|||
.struct xmlNode_children + 8 |
|||
xmlNode_last: // last child link |
|||
.struct xmlNode_last + 8 |
|||
xmlNode_parent: // child->parent link |
|||
.struct xmlNode_parent + 8 |
|||
xmlNode_next: // next sibling link |
|||
.struct xmlNode_next + 8 |
|||
xmlNode_prev: // previous sibling link |
|||
.struct xmlNode_prev + 8 |
|||
xmlNode_doc: // the containing document |
|||
.struct xmlNode_doc + 8 |
|||
xmlNode_ns: // pointer to the associated namespace |
|||
.struct xmlNode_ns + 8 |
|||
xmlNode_content: // the content |
|||
.struct xmlNode_content + 8 |
|||
xmlNode_properties: // properties list |
|||
.struct xmlNode_properties + 8 |
|||
xmlNode_nsDef: // namespace definitions on this node |
|||
.struct xmlNode_nsDef + 8 |
|||
xmlNode_psvi: // for type/PSVI informations |
|||
.struct xmlNode_psvi + 8 |
|||
xmlNode_line: // line number |
|||
.struct xmlNode_line + 4 |
|||
xmlNode_extra: // extra data for XPath/XSLT |
|||
.struct xmlNode_extra + 4 |
|||
xmlNode_fin: |
|||
/********************************************/ |
|||
/* structure xmlNodeSet*/ |
|||
.struct 0 |
|||
xmlNodeSet_nodeNr: // number of nodes in the set |
|||
.struct xmlNodeSet_nodeNr + 4 |
|||
xmlNodeSet_nodeMax: // size of the array as allocated |
|||
.struct xmlNodeSet_nodeMax + 4 |
|||
xmlNodeSet_nodeTab: // array of nodes in no particular order |
|||
.struct xmlNodeSet_nodeTab + 8 |
|||
xmlNodeSet_fin: |
|||
/********************************************/ |
|||
/* structure xmlXPathObject*/ |
|||
.struct 0 |
|||
xmlPathObj_type: // |
|||
.struct xmlPathObj_type + 8 |
|||
xmlPathObj_nodesetval: // |
|||
.struct xmlPathObj_nodesetval + 8 |
|||
xmlPathObj_boolval: // |
|||
.struct xmlPathObj_boolval + 8 |
|||
xmlPathObj_floatval: // |
|||
.struct xmlPathObj_floatval + 8 |
|||
xmlPathObj_stringval: // |
|||
.struct xmlPathObj_stringval + 8 |
|||
xmlPathObj_user: // |
|||
.struct xmlPathObj_user + 8 |
|||
xmlPathObj_index: // |
|||
.struct xmlPathObj_index + 8 |
|||
xmlPathObj_usex2: // |
|||
.struct xmlPathObj_usex2 + 8 |
|||
xmlPathObj_index2: // |
|||
.struct xmlPathObj_index2 + 8 |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessEndpgm: .asciz "\nNormal end of program.\n" |
|||
szMessDisVal: .asciz "\nDisplay set values.\n" |
|||
szMessDisArea: .asciz "\nDisplay area values.\n" |
|||
szFileName: .asciz "testXml.xml" |
|||
szMessError: .asciz "Error detected !!!!. \n" |
|||
szLibName: .asciz "name" |
|||
szLibPrice: .asciz "//price" |
|||
szLibExtName: .asciz "//name" |
|||
szCarriageReturn: .asciz "\n" |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
.align 4 |
|||
tbExtract: .skip 8 * NBMAXELEMENTS // result extract area |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: // entry of program |
|||
ldr x0,qAdrszFileName |
|||
bl xmlParseFile // create doc |
|||
cbz x0,99f // error ? |
|||
mov x19,x0 // doc address |
|||
mov x0,x19 // doc |
|||
bl xmlDocGetRootElement // get root |
|||
bl xmlFirstElementChild // get first section |
|||
bl xmlFirstElementChild // get first item |
|||
bl xmlFirstElementChild // get first name |
|||
bl xmlNodeGetContent // extract content |
|||
bl affichageMess // for display |
|||
ldr x0,qAdrszCarriageReturn |
|||
bl affichageMess |
|||
ldr x0,qAdrszMessDisVal |
|||
bl affichageMess |
|||
mov x0,x19 |
|||
ldr x1,qAdrszLibPrice // extract prices |
|||
bl extractValue |
|||
mov x0,x19 |
|||
ldr x1,qAdrszLibExtName // extract names |
|||
bl extractValue |
|||
ldr x0,qAdrszMessDisArea |
|||
bl affichageMess |
|||
mov x4,#0 // display string result area |
|||
ldr x5,qAdrtbExtract |
|||
1: |
|||
ldr x0,[x5,x4,lsl #3] |
|||
cbz x0,2f |
|||
bl affichageMess |
|||
ldr x0,qAdrszCarriageReturn |
|||
bl affichageMess |
|||
add x4,x4,1 |
|||
b 1b |
|||
2: |
|||
mov x0,x19 |
|||
bl xmlFreeDoc |
|||
bl xmlCleanupParser |
|||
ldr x0,qAdrszMessEndpgm |
|||
bl affichageMess |
|||
b 100f |
|||
99: // error |
|||
ldr x0,qAdrszMessError |
|||
bl affichageMess |
|||
100: // standard end of the program |
|||
mov x0,0 // return code |
|||
mov x8,EXIT // request to exit program |
|||
svc 0 // perform the system call |
|||
qAdrszMessError: .quad szMessError |
|||
qAdrszMessEndpgm: .quad szMessEndpgm |
|||
qAdrszLibName: .quad szLibName |
|||
qAdrszLibPrice: .quad szLibPrice |
|||
qAdrszCarriageReturn: .quad szCarriageReturn |
|||
qAdrszFileName: .quad szFileName |
|||
qAdrszLibExtName: .quad szLibExtName |
|||
qAdrtbExtract: .quad tbExtract |
|||
qAdrszMessDisVal: .quad szMessDisVal |
|||
qAdrszMessDisArea: .quad szMessDisArea |
|||
/******************************************************************/ |
|||
/* extract value of set */ |
|||
/******************************************************************/ |
|||
/* x0 contains the doc address |
|||
/* x1 contains the address of the libel to extract */ |
|||
extractValue: |
|||
stp x19,lr,[sp,-16]! // save registers |
|||
stp x20,x21,[sp,-16]! // save registers |
|||
stp x22,x23,[sp,-16]! // save registers |
|||
mov x20,x1 // save address libel |
|||
mov x19,x0 // save doc |
|||
bl xmlXPathNewContext // create context |
|||
mov x23,x0 // save context |
|||
mov x1,x0 |
|||
mov x0,x20 |
|||
bl xmlXPathEvalExpression |
|||
mov x21,x0 |
|||
mov x0,x23 |
|||
bl xmlXPathFreeContext // free context |
|||
cmp x21,#0 |
|||
beq 100f |
|||
ldr x14,[x21,#xmlPathObj_nodesetval] // values set |
|||
ldr w23,[x14,#xmlNodeSet_nodeNr] // set size |
|||
mov x22,#0 // index |
|||
ldr x20,[x14,#xmlNodeSet_nodeTab] // area of nodes |
|||
ldr x21,qAdrtbExtract |
|||
1: // start loop |
|||
ldr x3,[x20,x22,lsl #3] // load node |
|||
mov x0,x19 |
|||
ldr x1,[x3,#xmlNode_children] // load string value |
|||
mov x2,#1 |
|||
bl xmlNodeListGetString |
|||
str x0,[x21,x22,lsl #3] // store string pointer in area |
|||
bl affichageMess // and display string result |
|||
ldr x0,qAdrszCarriageReturn |
|||
bl affichageMess |
|||
add x22,x22,1 |
|||
cmp x22,x23 |
|||
blt 1b |
|||
100: |
|||
ldp x22,x23,[sp],16 // restaur 2 registers |
|||
ldp x20,x21,[sp],16 // restaur 2 registers |
|||
ldp x19,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/********************************************************/ |
|||
/* File Include fonctions */ |
|||
/********************************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly */ |
|||
.include "../includeARM64.inc" |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<pre> |
|||
Invisibility Cream |
|||
Display set values. |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
Display area values. |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
Normal end of program. |
|||
</pre> |
|||
=={{header|AppleScript}}== |
|||
'''Using System Events''' |
|||
''AppleScript has no-built in support for XPath, but it could be used via a 'do shell script' command. Here's a solution using Apple System Events. |
|||
<syntaxhighlight lang="applescript">set theXMLdata to "<inventory title=\"OmniCorp Store #45x10^3\"> |
|||
<section name=\"health\"> |
|||
<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> |
|||
</section> |
|||
<section name=\"food\"> |
|||
<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> |
|||
</section> |
|||
</inventory>" |
|||
on getElementValuesByName(theXML, theNameToFind) |
|||
set R to {} |
|||
tell application "System Events" |
|||
repeat with i in theXML |
|||
set {theName, theElements} to {i's name, i's XML elements} |
|||
if (count of theElements) > 0 then set R to R & my getElementValuesByName(theElements, theNameToFind) |
|||
if theName = theNameToFind then set R to R & i's value |
|||
end repeat |
|||
end tell |
|||
return R |
|||
end getElementValuesByName |
|||
on getBlock(theXML, theItem, theInstance) |
|||
set text item delimiters to "" |
|||
repeat with i from 1 to theInstance |
|||
set {R, blockStart, blockEnd} to {{}, "<" & theItem & space, "</" & theItem & ">"} |
|||
set x to offset of blockStart in theXML |
|||
if x = 0 then exit repeat |
|||
set y to offset of blockEnd in (characters x thru -1 of theXML as string) |
|||
if y = 0 then exit repeat |
|||
set R to characters x thru (x + y + (length of blockEnd) - 2) of theXML as string |
|||
set theXML to characters (y + (length of blockEnd)) thru -1 of theXML as string |
|||
end repeat |
|||
return R |
|||
end getBlock |
|||
tell application "System Events" |
|||
set xmlData to make new XML data with properties {name:"xmldata", text:theXMLdata} |
|||
return my getBlock(xmlData's text, "item", 1) -- Solution to part 1 of problem. |
|||
return my getElementValuesByName(xmlData's contents, "name") -- Solution to part 2 of problem. |
|||
return my getElementValuesByName(xmlData's contents, "price") -- Solution to part 3 of problem. |
|||
end tell</syntaxhighlight>Output for the three results (respectively):<syntaxhighlight lang="applescript">"<item upc=\"123456789\" stock=\"12\"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item>" |
|||
{"Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"} |
|||
{"14.50", "23.99", "4.95", "3.56"}</syntaxhighlight> |
|||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi}} |
|||
<syntaxhighlight lang="arm assembly"> |
|||
/* ARM assembly Raspberry PI */ |
|||
/* program xpathXml.s */ |
|||
/* Constantes */ |
|||
.equ STDOUT, 1 @ Linux output console |
|||
.equ EXIT, 1 @ Linux syscall |
|||
.equ WRITE, 4 @ Linux syscall |
|||
.equ NBMAXELEMENTS, 100 |
|||
/*******************************************/ |
|||
/* Structures */ |
|||
/********************************************/ |
|||
/* structure xmlNode*/ |
|||
.struct 0 |
|||
xmlNode_private: @ application data |
|||
.struct xmlNode_private + 4 |
|||
xmlNode_type: @ type number, must be second ! |
|||
.struct xmlNode_type + 4 |
|||
xmlNode_name: @ the name of the node, or the entity |
|||
.struct xmlNode_name + 4 |
|||
xmlNode_children: @ parent->childs link |
|||
.struct xmlNode_children + 4 |
|||
xmlNode_last: @ last child link |
|||
.struct xmlNode_last + 4 |
|||
xmlNode_parent: @ child->parent link |
|||
.struct xmlNode_parent + 4 |
|||
xmlNode_next: @ next sibling link |
|||
.struct xmlNode_next + 4 |
|||
xmlNode_prev: @ previous sibling link |
|||
.struct xmlNode_prev + 4 |
|||
xmlNode_doc: @ the containing document |
|||
.struct xmlNode_doc + 4 |
|||
xmlNode_ns: @ pointer to the associated namespace |
|||
.struct xmlNode_ns + 4 |
|||
xmlNode_content: @ the content |
|||
.struct xmlNode_content + 4 |
|||
xmlNode_properties: @ properties list |
|||
.struct xmlNode_properties + 4 |
|||
xmlNode_nsDef: @ namespace definitions on this node |
|||
.struct xmlNode_nsDef + 4 |
|||
xmlNode_psvi: @ for type/PSVI informations |
|||
.struct xmlNode_psvi + 4 |
|||
xmlNode_line: @ line number |
|||
.struct xmlNode_line + 4 |
|||
xmlNode_extra: @ extra data for XPath/XSLT |
|||
.struct xmlNode_extra + 4 |
|||
xmlNode_fin: |
|||
/********************************************/ |
|||
/* structure xmlNodeSet*/ |
|||
.struct 0 |
|||
xmlNodeSet_nodeNr: @ number of nodes in the set |
|||
.struct xmlNodeSet_nodeNr + 4 |
|||
xmlNodeSet_nodeMax: @ size of the array as allocated |
|||
.struct xmlNodeSet_nodeMax + 4 |
|||
xmlNodeSet_nodeTab: @ array of nodes in no particular order |
|||
.struct xmlNodeSet_nodeTab + 4 |
|||
xmlNodeSet_fin: |
|||
/********************************************/ |
|||
/* structure xmlXPathObject*/ |
|||
.struct 0 |
|||
xmlPathObj_type: @ |
|||
.struct xmlPathObj_type + 4 |
|||
xmlPathObj_nodesetval: @ |
|||
.struct xmlPathObj_nodesetval + 4 |
|||
xmlPathObj_boolval: @ |
|||
.struct xmlPathObj_boolval + 4 |
|||
xmlPathObj_floatval: @ |
|||
.struct xmlPathObj_floatval + 4 |
|||
xmlPathObj_stringval: @ |
|||
.struct xmlPathObj_stringval + 4 |
|||
xmlPathObj_user: @ |
|||
.struct xmlPathObj_user + 4 |
|||
xmlPathObj_index: @ |
|||
.struct xmlPathObj_index + 4 |
|||
xmlPathObj_user2: @ |
|||
.struct xmlPathObj_user2 + 4 |
|||
xmlPathObj_index2: @ |
|||
.struct xmlPathObj_index2 + 4 |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessEndpgm: .asciz "\nNormal end of program.\n" |
|||
szMessDisVal: .asciz "\nDisplay set values.\n" |
|||
szMessDisArea: .asciz "\nDisplay area values.\n" |
|||
szFileName: .asciz "testXml.xml" |
|||
szMessError: .asciz "Error detected !!!!. \n" |
|||
szLibName: .asciz "name" |
|||
szLibPrice: .asciz "//price" |
|||
szLibExtName: .asciz "//name" |
|||
szCarriageReturn: .asciz "\n" |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
.align 4 |
|||
tbExtract: .skip 4 * NBMAXELEMENTS @ result extract area |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
ldr r0,iAdrszFileName |
|||
bl xmlParseFile @ create doc |
|||
mov r9,r0 @ doc address |
|||
mov r0,r9 @ doc |
|||
bl xmlDocGetRootElement @ get root |
|||
bl xmlFirstElementChild @ get first section |
|||
bl xmlFirstElementChild @ get first item |
|||
bl xmlFirstElementChild @ get first name |
|||
bl xmlNodeGetContent @ extract content |
|||
bl affichageMess @ for display |
|||
ldr r0,iAdrszCarriageReturn |
|||
bl affichageMess |
|||
ldr r0,iAdrszMessDisVal |
|||
bl affichageMess |
|||
mov r0,r9 |
|||
ldr r1,iAdrszLibPrice @ extract prices |
|||
bl extractValue |
|||
mov r0,r9 |
|||
ldr r1,iAdrszLibExtName @ extact names |
|||
bl extractValue |
|||
ldr r0,iAdrszMessDisArea |
|||
bl affichageMess |
|||
mov r4,#0 @ display string result area |
|||
ldr r5,iAdrtbExtract |
|||
1: |
|||
ldr r0,[r5,r4,lsl #2] |
|||
cmp r0,#0 |
|||
beq 2f |
|||
bl affichageMess |
|||
ldr r0,iAdrszCarriageReturn |
|||
bl affichageMess |
|||
add r4,#1 |
|||
b 1b |
|||
2: |
|||
mov r0,r9 |
|||
bl xmlFreeDoc |
|||
bl xmlCleanupParser |
|||
ldr r0,iAdrszMessEndpgm |
|||
bl affichageMess |
|||
b 100f |
|||
99: |
|||
@ error |
|||
ldr r0,iAdrszMessError |
|||
bl affichageMess |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrszMessError: .int szMessError |
|||
iAdrszMessEndpgm: .int szMessEndpgm |
|||
iAdrszLibName: .int szLibName |
|||
iAdrszLibPrice: .int szLibPrice |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrszFileName: .int szFileName |
|||
iAdrszLibExtName: .int szLibExtName |
|||
iAdrtbExtract: .int tbExtract |
|||
iAdrszMessDisVal: .int szMessDisVal |
|||
iAdrszMessDisArea: .int szMessDisArea |
|||
/******************************************************************/ |
|||
/* extract value of set */ |
|||
/******************************************************************/ |
|||
/* r0 contains the doc address |
|||
/* r1 contains the address of the libel to extract */ |
|||
extractValue: |
|||
push {r1-r10,lr} @ save registres |
|||
mov r4,r1 @ save address libel |
|||
mov r9,r0 @ save doc |
|||
ldr r8,iAdrtbExtract |
|||
bl xmlXPathNewContext @ create context |
|||
mov r10,r0 |
|||
mov r1,r0 |
|||
mov r0,r4 |
|||
bl xmlXPathEvalExpression |
|||
mov r5,r0 |
|||
mov r0,r10 |
|||
bl xmlXPathFreeContext @ free context |
|||
cmp r5,#0 |
|||
beq 100f |
|||
ldr r4,[r5,#xmlPathObj_nodesetval] @ values set |
|||
ldr r6,[r4,#xmlNodeSet_nodeNr] @ set size |
|||
mov r7,#0 @ index |
|||
ldr r4,[r4,#xmlNodeSet_nodeTab] @ area of nods |
|||
1: @ start loop |
|||
ldr r3,[r4,r7,lsl #2] @ load node |
|||
mov r0,r9 |
|||
ldr r1,[r3,#xmlNode_children] @ load string value |
|||
mov r2,#1 |
|||
bl xmlNodeListGetString |
|||
str r0,[r8,r7,lsl #2] @ store string pointer in area |
|||
bl affichageMess @ and display string result |
|||
ldr r0,iAdrszCarriageReturn |
|||
bl affichageMess |
|||
add r7,#1 |
|||
cmp r7,r6 |
|||
blt 1b |
|||
100: |
|||
pop {r1-r10,lr} @ restaur registers */ |
|||
bx lr @ return |
|||
/******************************************************************/ |
|||
/* display text with size calculation */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of the message */ |
|||
affichageMess: |
|||
push {r0,r1,r2,r7,lr} @ save registres |
|||
mov r2,#0 @ counter length |
|||
1: @ loop length calculation |
|||
ldrb r1,[r0,r2] @ read octet start position + index |
|||
cmp r1,#0 @ if 0 its over |
|||
addne r2,r2,#1 @ else add 1 in the length |
|||
bne 1b @ and loop |
|||
@ so here r2 contains the length of the message |
|||
mov r1,r0 @ address message in r1 |
|||
mov r0,#STDOUT @ code to write to the standard output Linux |
|||
mov r7, #WRITE @ code call system "write" |
|||
svc #0 @ call systeme |
|||
pop {r0,r1,r2,r7,lr} @ restaur registers */ |
|||
bx lr @ return |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
<pre> |
|||
Invisibility Cream |
|||
Display set values. |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
Display area values. |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
Normal end of program. |
|||
</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
With regular expressions |
With regular expressions |
||
<syntaxhighlight lang="autohotkey">FileRead, inventory, xmlfile.xml |
|||
<lang AutoHotkey> |
|||
FileRead, inventory, xmlfile.xml |
|||
RegExMatch(inventory, "<item.*?</item>", item1) |
RegExMatch(inventory, "<item.*?</item>", item1) |
||
Line 47: | Line 628: | ||
While, pos := RegExMatch(inventory, "<name>.*?</name>", name, pos + 1) |
While, pos := RegExMatch(inventory, "<name>.*?</name>", name, pos + 1) |
||
names .= name . "`n" |
names .= name . "`n" |
||
MsgBox % names |
MsgBox % names</syntaxhighlight> |
||
</lang> |
|||
{{libheader|AHK XPath}} |
{{libheader|AHK XPath}} |
||
<syntaxhighlight lang="autohotkey">#Include xpath.ahk |
|||
<lang AutoHotkey> |
|||
#Include xpath.ahk |
|||
xpath_load(doc, "xmlfile.xml") |
xpath_load(doc, "xmlfile.xml") |
||
Line 65: | Line 644: | ||
; Get an array of all the "name" elements |
; Get an array of all the "name" elements |
||
MsgBox % xpath(doc, "/inventory/section/item/name") |
MsgBox % xpath(doc, "/inventory/section/item/name")</syntaxhighlight> |
||
</lang> |
|||
=={{header| |
=={{header|Bracmat}}== |
||
<syntaxhighlight lang="bracmat">{Retrieve the first "item" element} |
|||
<lang csharp> XmlReader XReader; |
|||
( nestML$(get$("doc.xml",X,ML)) |
|||
: ? |
|||
( inventory |
|||
. ?,? (section.?,? ((item.?):?item) ?) ? |
|||
) |
|||
? |
|||
& out$(toML$!item) |
|||
) |
|||
{Perform an action on each "price" element (print it out)} |
|||
( nestML$(get$("doc.xml",X,ML)) |
|||
: ? |
|||
( inventory |
|||
. ? |
|||
, ? |
|||
( section |
|||
. ? |
|||
, ? |
|||
( item |
|||
. ? |
|||
, ? |
|||
( price |
|||
. ? |
|||
, ?price |
|||
& out$!price |
|||
& ~ |
|||
) |
|||
? |
|||
) |
|||
? |
|||
) |
|||
? |
|||
) |
|||
? |
|||
| |
|||
) |
|||
{Get an array of all the "name" elements} |
|||
( :?anArray |
|||
& nestML$(get$("doc.xml",X,ML)) |
|||
: ? |
|||
( inventory |
|||
. ? |
|||
, ? |
|||
( section |
|||
. ? |
|||
, ? |
|||
( item |
|||
. ? |
|||
, ? |
|||
( name |
|||
. ? |
|||
, ?name |
|||
& !anArray !name:?anArray |
|||
& ~ |
|||
) |
|||
? |
|||
) |
|||
? |
|||
) |
|||
? |
|||
) |
|||
? |
|||
| out$!anArray {Not truly an array, but a list.} |
|||
);</syntaxhighlight> |
|||
=={{header|C}}== |
|||
{{libheader|LibXML}} |
|||
Takes XML document and XPath expression as inputs and prints results, usage is printed if invoked incorrectly. |
|||
<syntaxhighlight lang="c"> |
|||
#include <libxml/parser.h> |
|||
#include <libxml/xpath.h> |
|||
xmlDocPtr getdoc (char *docname) { |
|||
xmlDocPtr doc; |
|||
doc = xmlParseFile(docname); |
|||
return doc; |
|||
} |
|||
xmlXPathObjectPtr getnodeset (xmlDocPtr doc, xmlChar *xpath){ |
|||
xmlXPathContextPtr context; |
|||
xmlXPathObjectPtr result; |
|||
context = xmlXPathNewContext(doc); |
|||
result = xmlXPathEvalExpression(xpath, context); |
|||
xmlXPathFreeContext(context); |
|||
return result; |
|||
} |
|||
int main(int argc, char **argv) { |
|||
if (argc <= 2) { |
|||
printf("Usage: %s <XML Document Name> <XPath expression>\n", argv[0]); |
|||
return 0; |
|||
} |
|||
char *docname; |
|||
xmlDocPtr doc; |
|||
xmlChar *xpath = (xmlChar*) argv[2]; |
|||
xmlNodeSetPtr nodeset; |
|||
xmlXPathObjectPtr result; |
|||
int i; |
|||
xmlChar *keyword; |
|||
docname = argv[1]; |
|||
doc = getdoc(docname); |
|||
result = getnodeset (doc, xpath); |
|||
if (result) { |
|||
nodeset = result->nodesetval; |
|||
for (i=0; i < nodeset->nodeNr; i++) { |
|||
xmlNodePtr titleNode = nodeset->nodeTab[i]; |
|||
keyword = xmlNodeListGetString(doc, titleNode->xmlChildrenNode, 1); |
|||
printf("Value %d: %s\n",i+1, keyword); |
|||
xmlFree(keyword); |
|||
} |
|||
xmlXPathFreeObject (result); |
|||
} |
|||
xmlFreeDoc(doc); |
|||
xmlCleanupParser(); |
|||
return 0; |
|||
} |
|||
</syntaxhighlight> |
|||
testXML.xml contains the XML mentioned in the task description. Code must be compiled with the correct flags. |
|||
<pre> |
|||
C:\rosettaCode>xPather.exe testXML.xml //price |
|||
Value 1: 14.50 |
|||
Value 2: 23.99 |
|||
Value 3: 4.95 |
|||
Value 4: 3.56 |
|||
C:\rosettaCode>xPather.exe testXML.xml //name |
|||
Value 1: Invisibility Cream |
|||
Value 2: Levitation Salve |
|||
Value 3: Blork and Freen Instameal |
|||
Value 4: Grob winglets |
|||
</pre> |
|||
=={{header|C sharp}}== |
|||
<syntaxhighlight 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);</syntaxhighlight> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
<lang C++>#include <vector> |
|||
The following code uses each of the three tasks given to demonstrate a different method of handling the resulting node set from an XPath query. |
|||
#include <string> |
|||
{{libheader|LibXML}} |
|||
<syntaxhighlight lang="cpp">#include <cassert> |
|||
#include <cstdlib> |
|||
#include <iostream> |
#include <iostream> |
||
#include < |
#include <stdexcept> |
||
#include < |
#include <utility> |
||
#include < |
#include <vector> |
||
#include <libxml/parser.h> |
|||
int main( ) { |
|||
#include <libxml/tree.h> |
|||
const std::string xmltext( |
|||
#include <libxml/xmlerror.h> |
|||
"<inventory title=\"OmniCorp Store #45x10^3\">" |
|||
#include <libxml/xmlstring.h> |
|||
"<section name=\"health\">" |
|||
#include <libxml/xmlversion.h> |
|||
"<item upc=\"123456789\" stock=\"12\">" |
|||
#include <libxml/xpath.h> |
|||
"<name>Invisibility Cream</name>" |
|||
"<price>14.50</price>" |
|||
#ifndef LIBXML_XPATH_ENABLED |
|||
"<description>Makes you invisible</description>" |
|||
# error libxml was not configured with XPath support |
|||
"</item>" |
|||
#endif |
|||
"<item upc=\"445322344\" stock=\"18\">" |
|||
"<name>Levitation Salve</name>" |
|||
// Because libxml2 is a C library, we need a couple things to make it work |
|||
"<price>23.99</price>" |
|||
// well with modern C++: |
|||
"<description>Levitate yourself for up to 3 hours per application</description>" |
|||
// 1) a ScopeGuard-like type to handle cleanup functions; and |
|||
"</item>" |
|||
// 2) an exception type that transforms the library's errors. |
|||
"</section>" |
|||
"<section name=\"food\">" |
|||
// ScopeGuard-like type to handle C library cleanup functions. |
|||
"<item upc=\"485672034\" stock=\"653\">" |
|||
template <typename F> |
|||
"<name>Blork and Freen Instameal</name>" |
|||
class [[nodiscard]] scope_exit |
|||
"<price>4.95</price>" |
|||
{ |
|||
"<description>A tasty meal in a tablet; just add water</description>" |
|||
public: |
|||
"</item>" |
|||
// C++20: Constructor can (and should) be [[nodiscard]]. |
|||
"<item upc=\"132957764\" stock=\"44\">" |
|||
/*[[nodiscard]]*/ constexpr explicit scope_exit(F&& f) : |
|||
"<name>Grob winglets</name>" |
|||
f_{std::move(f)} |
|||
"<price>3.56</price>" |
|||
{} |
|||
"<description>Tender winglets of Grob. Just add water</description>" |
|||
"</item>" |
|||
~scope_exit() |
|||
"</section>" |
|||
{ |
|||
"</inventory>" ) ; |
|||
f_(); |
|||
std::string::size_type found = xmltext.find( "<item" , 0 ) ; //beginning of first item |
|||
} |
|||
std::string::size_type foundnext = xmltext.find( "</item>" , found + 5 ) ; //and its end |
|||
std::cout << "The first item is\n" << xmltext.substr( found + 5 , foundnext - ( found + 5 ) ) << '\n' ; |
|||
// Non-copyable, non-movable. |
|||
std::string::const_iterator start , end ; |
|||
scope_exit(scope_exit const&) = delete; |
|||
start = xmltext.begin( ) ; |
|||
scope_exit(scope_exit&&) = delete; |
|||
end = xmltext.end( ) ; |
|||
auto operator=(scope_exit const&) -> scope_exit& = delete; |
|||
boost::match_results<std::string::const_iterator> what ; |
|||
auto operator=(scope_exit&&) -> scope_exit& = delete; |
|||
boost::regex pricefind( "<price>(\\d+\\.?\\d+)</price>" ) ;//this regex finds the prices |
|||
start = xmltext.begin( ) ; |
|||
private: |
|||
std::cout << "The prices are:\n" ; |
|||
F f_; |
|||
while ( boost::regex_search( start , end , what , pricefind ) ) { |
|||
}; |
|||
std::string price( what[ 1 ].first , what[ 1 ].second ) ;//find the first price |
|||
std::cout << price << std::endl ; |
|||
// Exception that gets last libxml2 error. |
|||
start = what[ 1 ].second ; //continue search after first price found |
|||
class libxml_error : public std::runtime_error |
|||
{ |
|||
public: |
|||
libxml_error() : libxml_error(std::string{}) {} |
|||
explicit libxml_error(std::string message) : |
|||
std::runtime_error{make_message_(std::move(message))} |
|||
{} |
|||
private: |
|||
static auto make_message_(std::string message) -> std::string |
|||
{ |
|||
if (auto const last_error = ::xmlGetLastError(); last_error) |
|||
{ |
|||
if (not message.empty()) |
|||
message += ": "; |
|||
message += last_error->message; |
|||
} |
|||
return message; |
|||
} |
|||
}; |
|||
auto main() -> int |
|||
{ |
|||
try |
|||
{ |
|||
// Initialize libxml. |
|||
::xmlInitParser(); |
|||
LIBXML_TEST_VERSION |
|||
auto const libxml_cleanup = scope_exit{[] { ::xmlCleanupParser(); }}; |
|||
// Load and parse XML document. |
|||
auto const doc = ::xmlParseFile("test.xml"); |
|||
if (not doc) |
|||
throw libxml_error{"failed to load document"}; |
|||
auto const doc_cleanup = scope_exit{[doc] { ::xmlFreeDoc(doc); }}; |
|||
// Create XPath context for document. |
|||
auto const xpath_context = ::xmlXPathNewContext(doc); |
|||
if (not xpath_context) |
|||
throw libxml_error{"failed to create XPath context"}; |
|||
auto const xpath_context_cleanup = scope_exit{[xpath_context] |
|||
{ ::xmlXPathFreeContext(xpath_context); }}; |
|||
// Task 1 ============================================================ |
|||
{ |
|||
std::cout << "Task 1:\n"; |
|||
auto const xpath = |
|||
reinterpret_cast<::xmlChar const*>(u8"//item[1]"); |
|||
// Create XPath object (same for every task). |
|||
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context); |
|||
if (not xpath_obj) |
|||
throw libxml_error{"failed to evaluate XPath"}; |
|||
auto const xpath_obj_cleanup = scope_exit{[xpath_obj] |
|||
{ ::xmlXPathFreeObject(xpath_obj); }}; |
|||
// 'result' a xmlNode* to the desired node, or nullptr if it |
|||
// doesn't exist. If not nullptr, the node is owned by 'doc'. |
|||
auto const result = xmlXPathNodeSetItem(xpath_obj->nodesetval, 0); |
|||
if (result) |
|||
std::cout << '\t' << "node found" << '\n'; |
|||
else |
|||
std::cout << '\t' << "node not found" << '\n'; |
|||
} |
|||
// Task 2 ============================================================ |
|||
{ |
|||
std::cout << "Task 2:\n"; |
|||
auto const xpath = |
|||
reinterpret_cast<::xmlChar const*>(u8"//price/text()"); |
|||
// Create XPath object (same for every task). |
|||
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context); |
|||
if (not xpath_obj) |
|||
throw libxml_error{"failed to evaluate XPath"}; |
|||
auto const xpath_obj_cleanup = scope_exit{[xpath_obj] |
|||
{ ::xmlXPathFreeObject(xpath_obj); }}; |
|||
// Printing the results. |
|||
auto const count = |
|||
xmlXPathNodeSetGetLength(xpath_obj->nodesetval); |
|||
for (auto i = decltype(count){0}; i < count; ++i) |
|||
{ |
|||
auto const node = |
|||
xmlXPathNodeSetItem(xpath_obj->nodesetval, i); |
|||
assert(node); |
|||
auto const content = XML_GET_CONTENT(node); |
|||
assert(content); |
|||
// Note that reinterpret_cast here is a Bad Idea, because |
|||
// 'content' is UTF-8 encoded, which may or may not be the |
|||
// encoding cout expects. A *PROPER* solution would translate |
|||
// content to the correct encoding (or at least verify that |
|||
// UTF-8 *is* the correct encoding). |
|||
// |
|||
// But this "works" well enough for illustration. |
|||
std::cout << "\n\t" << reinterpret_cast<char const*>(content); |
|||
} |
|||
std::cout << '\n'; |
|||
} |
|||
// Task 3 ============================================================ |
|||
{ |
|||
std::cout << "Task 3:\n"; |
|||
auto const xpath = |
|||
reinterpret_cast<::xmlChar const*>(u8"//name"); |
|||
// Create XPath object (same for every task). |
|||
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context); |
|||
if (not xpath_obj) |
|||
throw libxml_error{"failed to evaluate XPath"}; |
|||
auto const xpath_obj_cleanup = scope_exit{[xpath_obj] |
|||
{ ::xmlXPathFreeObject(xpath_obj); }}; |
|||
// 'results' is a vector of pointers to the result nodes. The |
|||
// nodes pointed to are owned by 'doc'. |
|||
auto const results = [ns=xpath_obj->nodesetval]() |
|||
{ |
|||
auto v = std::vector<::xmlNode*>{}; |
|||
if (ns && ns->nodeTab) |
|||
v.assign(ns->nodeTab, ns->nodeTab + ns->nodeNr); |
|||
return v; |
|||
}(); |
|||
std::cout << '\t' << "set of " << results.size() |
|||
<< " node(s) found" << '\n'; |
|||
} |
|||
} |
|||
catch (std::exception const& x) |
|||
{ |
|||
std::cerr << "ERROR: " << x.what() << '\n'; |
|||
return EXIT_FAILURE; |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Caché ObjectScript}}== |
|||
<syntaxhighlight lang="cos">Class XML.Inventory [ Abstract ] |
|||
{ |
|||
XData XMLData |
|||
{ |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
} |
|||
ClassMethod QueryXMLDoc(Output names As %List) As %Status |
|||
{ |
|||
// get xml stream from the 'XData' block contained in this class |
|||
Set xdata=##class(%Dictionary.CompiledXData).%OpenId($this_"||XMLData",, .sc) |
|||
If $$$ISERR(sc) Quit sc |
|||
Set sc=##class(%XML.XPATH.Document).CreateFromStream(xdata.Data, .xdoc) |
|||
If $$$ISERR(sc) Quit sc |
|||
// retrieve the first 'item' element |
|||
Set sc=xdoc.EvaluateExpression("//section[1]", "item[1]", .res) |
|||
// perform an action on each 'price' element (print it out) |
|||
Set sc=xdoc.EvaluateExpression("//price", "text()", .res) |
|||
If $$$ISERR(sc) Quit sc |
|||
For i=1:1:res.Count() { |
|||
If i>1 Write ", " |
|||
Write res.GetAt(i).Value |
|||
} |
} |
||
start = xmltext.begin( ) ; |
|||
// get an array of all the 'name' elements |
|||
std::vector<std::string> names ; |
|||
Set sc=xdoc.EvaluateExpression("//item", "name", .res) |
|||
boost::regex namefind( "<name>(.+?)</name>" ) ; //find characters, be greedy! |
|||
If $$$ISERR(sc) Quit sc |
|||
while ( boost::regex_search ( start , end , what , namefind ) ) { |
|||
Set key="" |
|||
std::string name ( what[ 1 ].first , what[ 1 ].second ) ; |
|||
Do { |
|||
names.push_back( name ) ; |
|||
Set dom=res.GetNext(.key) |
|||
start = what[ 1 ].second ; |
|||
If '$IsObject(dom) Quit |
|||
} |
|||
While dom.Read() { |
|||
std::cout << "The following name elements were found in the xml string:\n" ; |
|||
If dom.HasValue Set $List(names, key)=dom.Value |
|||
std::copy( names.begin( ) , names.end( ) , std::ostream_iterator<std::string>( std::cout , "\n" )) ; |
|||
} |
|||
} While key'="" |
|||
// finished |
|||
Quit $$$OK |
|||
} |
} |
||
</lang> |
|||
}</syntaxhighlight> |
|||
{{out|Examples}} |
|||
<pre> |
|||
USER>Do ##class(XML.Inventory).QueryXMLDoc(.list) |
|||
14.50, 23.99, 4.95, 3.56 |
|||
USER>Write $ListToString(list, ", ") |
|||
Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets |
|||
</pre> |
|||
=={{header|CoffeeScript}}== |
|||
<div class='mw-collapsible mw-collapsed'> |
|||
<syntaxhighlight lang="coffeescript"> |
|||
doc = new DOMParser().parseFromString ' |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
', 'text/xml' |
|||
</syntaxhighlight> |
|||
</div> |
|||
<nowiki>#</nowiki> "doc" is the XML as a Document object. Click expand to see parsing code ⇒ |
|||
<syntaxhighlight lang="coffeescript"> |
|||
# Retrieve the first "item" element |
|||
doc.evaluate('//item', doc, {}, 7, {}).snapshotItem 0 |
|||
# Perform an action on each "price" element (print it out) |
|||
prices = doc.evaluate "//price", doc, {}, 7, {} |
|||
for i in [0...prices.snapshotLength] by 1 |
|||
console.log prices.snapshotItem(i).textContent |
|||
# Get an array of all the "name" elements |
|||
names = doc.evaluate "//name", doc, {}, 7, {} |
|||
names = for i in [0...names.snapshotLength] by 1 |
|||
names.snapshotItem i |
|||
</syntaxhighlight> |
|||
=={{header|ColdFusion}}== |
=={{header|ColdFusion}}== |
||
<syntaxhighlight lang="cfm"><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#"></syntaxhighlight> |
|||
=={{header|Common Lisp}}== |
|||
{{libheader|plexippus-xpath}} |
|||
{{libheader|cxml}} |
|||
{{libheader|cxml-stp}} |
|||
<syntaxhighlight lang="lisp">(dolist (system '(:xpath :cxml-stp :cxml)) |
|||
(asdf:oos 'asdf:load-op system)) |
|||
(defparameter *doc* (cxml:parse-file "xml" (stp:make-builder))) |
|||
(xpath:first-node (xpath:evaluate "/inventory/section[1]/item[1]" *doc*)) |
|||
(xpath:do-node-set (node (xpath:evaluate "/inventory/section/item/price/text()" *doc*)) |
|||
(format t "~A~%" (stp:data node))) |
|||
(defun node-array (node-set) |
|||
(coerce (xpath:all-nodes node-set) 'vector)) |
|||
(node-array |
|||
(xpath:evaluate "/inventory/section/item/name" *doc*))</syntaxhighlight> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
It is important to note that the KXML library currently only supports XPath minimally. |
It is important to note that the KXML library currently only supports XPath minimally. |
||
{{libheader|KXML}} |
{{libheader|KXML}} |
||
<syntaxhighlight lang="d">import kxml.xml; |
|||
<lang d> |
|||
import kxml.xml; |
|||
char[]xmlinput = |
char[]xmlinput = |
||
"<inventory title=\"OmniCorp Store #45x10^3\"> |
"<inventory title=\"OmniCorp Store #45x10^3\"> |
||
Line 240: | Line 1,241: | ||
} |
} |
||
auto namearray = root.parseXPath("inventory/section/item/name"); |
auto namearray = root.parseXPath("inventory/section/item/name"); |
||
}</syntaxhighlight> |
|||
=={{header|Delphi}}== |
|||
<syntaxhighlight lang="delphi">program XMLXPath; |
|||
{$APPTYPE CONSOLE} |
|||
uses ActiveX, MSXML; |
|||
const |
|||
XML = |
|||
'<inventory title="OmniCorp Store #45x10^3">' + |
|||
' <section name="health">' + |
|||
' <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>' + |
|||
' </section>' + |
|||
' <section name="food">' + |
|||
' <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>' + |
|||
' </section>' + |
|||
'</inventory>'; |
|||
var |
|||
i: Integer; |
|||
s: string; |
|||
lXMLDoc: IXMLDOMDocument2; |
|||
lNodeList: IXMLDOMNodeList; |
|||
lNode: IXMLDOMNode; |
|||
lItemNames: array of string; |
|||
begin |
|||
CoInitialize(nil); |
|||
lXMLDoc := CoDOMDocument.Create; |
|||
lXMLDoc.setProperty('SelectionLanguage', 'XPath'); |
|||
lXMLDoc.loadXML(XML); |
|||
Writeln('First item node:'); |
|||
lNode := lXMLDoc.selectNodes('//item')[0]; |
|||
Writeln(lNode.xml); |
|||
Writeln(''); |
|||
lNodeList := lXMLDoc.selectNodes('//price'); |
|||
for i := 0 to lNodeList.length - 1 do |
|||
Writeln('Price = ' + lNodeList[i].text); |
|||
Writeln(''); |
|||
lNodeList := lXMLDoc.selectNodes('//item/name'); |
|||
SetLength(lItemNames, lNodeList.length); |
|||
for i := 0 to lNodeList.length - 1 do |
|||
lItemNames[i] := lNodeList[i].text; |
|||
for s in lItemNames do |
|||
Writeln('Item name = ' + s); |
|||
end.</syntaxhighlight> |
|||
Output: |
|||
<syntaxhighlight lang="text">First item node: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Price = 14.50 |
|||
Price = 23.99 |
|||
Price = 4.95 |
|||
Price = 3.56 |
|||
Item name = Invisibility Cream |
|||
Item name = Levitation Salve |
|||
Item name = Blork and Freen Instameal |
|||
Item name = Grob winglets</syntaxhighlight> |
|||
=={{header|E}}== |
|||
{{libheader|E-XML}} (currently a very early work in progress/draft library; design comments welcome) |
|||
<syntaxhighlight lang="e">? def xml__quasiParser := <import:org.switchb.e.xml.makeXMLQuasiParser>() |
|||
> def xpath__quasiParser := xml__quasiParser.xPathQuasiParser() |
|||
> null |
|||
? def doc := xml`<inventory title="OmniCorp Store #45x10^3"> |
|||
> <section name="health"> |
|||
> <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>n> |
|||
> </item> |
|||
> </section> |
|||
> <section name="food"> |
|||
> <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> |
|||
> </section> |
|||
> </inventory>` |
|||
# value: xml`...` |
|||
? doc[xpath`inventory/section/item`][0] |
|||
# value: xml`<item stock="12" upc="123456789"> |
|||
# <name>Invisibility Cream</name> |
|||
# <price>14.50</price> |
|||
# <description>Makes you invisible</description> |
|||
# </item>` |
|||
? for price in doc[xpath`inventory/section/item/price/text()`] { println(price :String) } |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
? doc[xpath`inventory/section/item/name`] |
|||
# value: [xml`<name>Invisibility Cream</name>`, |
|||
# xml`<name>Levitation Salve</name>`, |
|||
# xml`<name>Blork and Freen Instameal</name>`, |
|||
# xml`<name>Grob winglets</name>`] |
|||
</syntaxhighlight> |
|||
=={{header|Erlang}}== |
|||
{{libheader|xmerl}} |
|||
<syntaxhighlight lang="erlang"> |
|||
-module(xml_xpath). |
|||
-include_lib("xmerl/include/xmerl.hrl"). |
|||
-export([main/0]). |
|||
main() -> |
|||
XMLDocument = |
|||
"<inventory title=\"OmniCorp Store #45x10^3\"> |
|||
<section name=\"health\"> |
|||
<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> |
|||
</section> |
|||
<section name=\"food\"> |
|||
<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> |
|||
</section> |
|||
</inventory>", |
|||
{Document,_} = xmerl_scan:string(XMLDocument), |
|||
io:format("First item:\n~s\n", |
|||
[lists:flatten( |
|||
xmerl:export_simple( |
|||
[hd(xmerl_xpath:string("//item[1]", Document))], |
|||
xmerl_xml, [{prolog, ""}]))]), |
|||
io:format("Prices:\n"), |
|||
[ io:format("~s\n",[Content#xmlText.value]) |
|||
|| #xmlElement{content = [Content|_]} <- xmerl_xpath:string("//price", Document)], |
|||
io:format("Names:\n"), |
|||
[ Content#xmlText.value |
|||
|| #xmlElement{content = [Content|_]} <- xmerl_xpath:string("//name", Document)]. |
|||
</syntaxhighlight> |
|||
Output:<pre>First item: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Prices: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Names: |
|||
["Invisibility Cream","Levitation Salve", |
|||
"Blork and Freen Instameal","Grob winglets"] |
|||
</pre> |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="vbnet">Dim As String XML, item, price, nombre |
|||
Dim As Integer P1, P2 |
|||
'' Read the XML file |
|||
Open "test3.xml" For Input As #1 |
|||
XML = Input(Lof(1), #1) |
|||
Close #1 |
|||
'' Find the first 'item' element |
|||
P1 = Instr(XML, "<item ") |
|||
P2 = Instr(XML, "</item>") |
|||
item = Mid(XML, P1, P2-P1+7) |
|||
Print "The first 'item' element is:" |
|||
Print item |
|||
'' Find all 'price' elements |
|||
Print "The 'prices' are:" |
|||
P1 = 1 |
|||
Do |
|||
P1 = Instr(P1, XML, "<price>") |
|||
If P1 = 0 Then Exit Do |
|||
P2 = Instr(P1, XML, "</price>") |
|||
price = Mid(XML, P1+7, P2-P1-7) |
|||
Print price |
|||
P1 = P2 + 1 |
|||
Loop |
|||
'' Find all 'nombre' elements |
|||
Print !"\nThe 'names' are:" |
|||
P1 = 1 |
|||
Do |
|||
P1 = Instr(P1, XML, "<name>") |
|||
If P1 = 0 Then Exit Do |
|||
P2 = Instr(P1, XML, "</name>") |
|||
nombre = Mid(XML, P1+6, P2-P1-6) |
|||
Print nombre |
|||
P1 = P2 + 1 |
|||
Loop |
|||
Sleep</syntaxhighlight> |
|||
=={{header|F_Sharp|F#}}== |
|||
<syntaxhighlight lang="fsharp"> |
|||
open System.IO |
|||
open System.Xml.XPath |
|||
let xml = new StringReader(""" |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
""") |
|||
let nav = XPathDocument(xml).CreateNavigator() |
|||
// first "item"; throws if none exists |
|||
let item = nav.SelectSingleNode(@"//item[1]") |
|||
// apply a operation (print text value) to all price elements |
|||
for price in nav.Select(@"//price") do |
|||
printfn "%s" (price.ToString()) |
|||
// array of all name elements |
|||
let names = seq { for name in nav.Select(@"//name") do yield name } |> Seq.toArray</syntaxhighlight> |
|||
=={{header|Factor}}== |
|||
{{libheader|xml}} |
|||
{{libheader|xml.data}} |
|||
{{libheader|xml.traversal}} |
|||
<syntaxhighlight lang="factor"> |
|||
! Get first item element |
|||
"""<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory>""" string>xml "item" deep-tag-named |
|||
! Print out prices |
|||
"""<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory>""" string>xml "price" deep-tags-named [ children>> first ] map |
|||
! Array of all name elements |
|||
"""<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory>""" string>xml "name" deep-tags-named |
|||
</syntaxhighlight> |
|||
=={{header|Gastona}}== |
|||
The example uses the command XMELON which parses a XML file of any schema and stores its |
|||
contents into db tables. This parser is described in the article [http://web3.codeproject.com/Articles/680642/XMeLon-Schema XMeLon-Schema] |
|||
<syntaxhighlight lang="gastona">#javaj# |
|||
<frames> oSal, XML Path sample, 300, 400 |
|||
#data# |
|||
<xml> |
|||
//<inventory title="OmniCorp Store #45x10^3"> |
|||
// <section name="health"> |
|||
// <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> |
|||
// </section> |
|||
// <section name="food"> |
|||
// <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> |
|||
// </section> |
|||
//</inventory> |
|||
<DEEP_SQL_XML> |
|||
DEEP DB, SELECT, xmelon_data |
|||
,, path pathStr |
|||
,, tag tagStr |
|||
,, patCnt |
|||
,, dataPlace |
|||
,, value |
|||
#listix# |
|||
<main> |
|||
//parsing xml data ... |
|||
GEN, :mem datos, xml |
|||
XMELON, FILE2DB, :mem datos |
|||
// |
|||
//first item ... |
|||
// |
|||
// |
|||
LOOP, SQL,, //SELECT patCnt AS patITEM1 FROM (@<DEEP_SQL_XML>) WHERE path_pathStr == '/inventory/section/item' LIMIT 1 |
|||
,HEAD, //<item |
|||
,, LOOP, SQL,, //SELECT * FROM (@<DEEP_SQL_XML>) WHERE patCnt == @<patITEM1> AND dataPlace == 'A' |
|||
,, , LINK, "" |
|||
,, ,, // @<tag_tagStr>="@<value>" |
|||
,, //> |
|||
,, // |
|||
,, LOOP, SQL,, //SELECT * FROM (@<DEEP_SQL_XML>) WHERE patCnt == @<patITEM1> AND dataPlace != 'A' |
|||
,, ,, // <@<tag_tagStr>>@<value></@<tag_tagStr>> |
|||
,TAIL, // |
|||
,TAIL, //</item> |
|||
// |
|||
// |
|||
//report prices ... |
|||
// |
|||
LOOP, SQL,, //SELECT value FROM (@<DEEP_SQL_XML>) WHERE tag_tagStr == 'price' |
|||
, LINK, ", " |
|||
,, @<value> |
|||
// |
|||
//put names into a variable |
|||
// |
|||
VAR=, tabnames, "name" |
|||
LOOP, SQL,, //SELECT value FROM (@<DEEP_SQL_XML>) WHERE tag_tagStr == 'name' |
|||
, LINK, "" |
|||
,, VAR+, tabnames, @<value> |
|||
DUMP, data,, tabnames |
|||
</syntaxhighlight> |
|||
{{out|Output}} |
|||
<pre> |
|||
parsing xml data ... |
|||
first item ... |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
report prices ... |
|||
14.50, 23.99, 4.95, 3.56 |
|||
names into a variable |
|||
#data# |
|||
<tabnames> |
|||
//name |
|||
//health |
|||
//Invisibility Cream |
|||
//Levitation Salve |
|||
//food |
|||
//Blork and Freen Instameal |
|||
//Grob winglets |
|||
</pre> |
|||
=={{header|Go}}== |
|||
Using the standard <code>encoding/xml</code> package: |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"encoding/xml" |
|||
"fmt" |
|||
"log" |
|||
"os" |
|||
) |
|||
type Inventory struct { |
|||
XMLName xml.Name `xml:"inventory"` |
|||
Title string `xml:"title,attr"` |
|||
Sections []struct { |
|||
XMLName xml.Name `xml:"section"` |
|||
Name string `xml:"name,attr"` |
|||
Items []struct { |
|||
XMLName xml.Name `xml:"item"` |
|||
Name string `xml:"name"` |
|||
UPC string `xml:"upc,attr"` |
|||
Stock int `xml:"stock,attr"` |
|||
Price float64 `xml:"price"` |
|||
Description string `xml:"description"` |
|||
} `xml:"item"` |
|||
} `xml:"section"` |
|||
} |
} |
||
// To simplify main's error handling |
|||
</lang> |
|||
func printXML(s string, v interface{}) { |
|||
fmt.Println(s) |
|||
b, err := xml.MarshalIndent(v, "", "\t") |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
fmt.Println(string(b)) |
|||
fmt.Println() |
|||
} |
|||
func main() { |
|||
fmt.Println("Reading XML from standard input...") |
|||
var inv Inventory |
|||
dec := xml.NewDecoder(os.Stdin) |
|||
if err := dec.Decode(&inv); err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
// At this point, inv is Go struct with all the fields filled |
|||
// in from the XML data. Well-formed XML input that doesn't |
|||
// match the specification of the fields in the Go struct are |
|||
// discarded without error. |
|||
// We can reformat the parts we parsed: |
|||
//printXML("Got:", inv) |
|||
// 1. Retrieve first item: |
|||
item := inv.Sections[0].Items[0] |
|||
fmt.Println("item variable:", item) |
|||
printXML("As XML:", item) |
|||
// 2. Action on each price: |
|||
fmt.Println("Prices:") |
|||
var totalValue float64 |
|||
for _, s := range inv.Sections { |
|||
for _, i := range s.Items { |
|||
fmt.Println(i.Price) |
|||
totalValue += i.Price * float64(i.Stock) |
|||
} |
|||
} |
|||
fmt.Println("Total inventory value:", totalValue) |
|||
fmt.Println() |
|||
// 3. Slice of all the names: |
|||
var names []string |
|||
for _, s := range inv.Sections { |
|||
for _, i := range s.Items { |
|||
names = append(names, i.Name) |
|||
} |
|||
} |
|||
fmt.Printf("names: %q\n", names) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Reading XML from standard input... |
|||
item variable: {{ item} Invisibility Cream 123456789 12 14.5 Makes you invisible} |
|||
As XML: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.5</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Prices: |
|||
14.5 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Total inventory value: 3994.81 |
|||
names: ["Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets"] |
|||
</pre> |
|||
{{libheader|xmlpath}} |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"fmt" |
|||
"os" |
|||
"launchpad.net/xmlpath" |
|||
) |
|||
func main() { |
|||
f, err := os.Open("test3.xml") |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
return |
|||
} |
|||
n, err := xmlpath.Parse(f) |
|||
f.Close() |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
return |
|||
} |
|||
q1 := xmlpath.MustCompile("//item") |
|||
if _, ok := q1.String(n); !ok { |
|||
fmt.Println("no item") |
|||
} |
|||
q2 := xmlpath.MustCompile("//price") |
|||
for it := q2.Iter(n); it.Next(); { |
|||
fmt.Println(it.Node()) |
|||
} |
|||
q3 := xmlpath.MustCompile("//name") |
|||
names := []*xmlpath.Node{} |
|||
for it := q3.Iter(n); it.Next(); { |
|||
names = append(names, it.Node()) |
|||
} |
|||
if len(names) == 0 { |
|||
fmt.Println("no names") |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
</pre> |
|||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
< |
<syntaxhighlight lang="groovy">def inventory = new XmlSlurper().parseText("<inventory...") //optionally parseText(new File("inv.xml").text) |
||
def firstItem = inventory.section.item[0] //1. first item |
def firstItem = inventory.section.item[0] //1. first item |
||
inventory.section.item.price.each { println it } //2. print each price |
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</ |
def allNamesArray = inventory.section.item.name.collect {it} //3. collect item names into an array</syntaxhighlight> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Data.List |
||
import Control.Arrow |
import Control.Arrow |
||
import Control.Monad |
import Control.Monad |
||
Line 275: | Line 1,925: | ||
putStrLn "\n== Names ==\n" |
putStrLn "\n== Names ==\n" |
||
print $ getsingleLineItems "name" xmlText</ |
print $ getsingleLineItems "name" xmlText</syntaxhighlight> |
||
Using the Haskell XML Toolkit (HXT): |
|||
<syntaxhighlight lang="haskell">{-# LANGUAGE Arrows #-} |
|||
import Text.XML.HXT.Arrow |
|||
{- For HXT version >= 9.0, use instead: |
|||
import Text.XML.HXT.Core |
|||
-} |
|||
deepElem name = deep (isElem >>> hasName name) |
|||
process = proc doc -> do |
|||
item <- single (deepElem "item") -< doc |
|||
_ <- listA (arrIO print <<< deepElem "price") -< doc |
|||
names <- listA (deepElem "name") -< doc |
|||
returnA -< (item, names) |
|||
main = do |
|||
[(item, names)] <- runX (readDocument [] "xmlpath.xml" >>> process) |
|||
print item |
|||
print names</syntaxhighlight> |
|||
=={{header|HicEst}}== |
|||
<syntaxhighlight lang="hicest">CHARACTER xml*1000, output*1000 |
|||
READ(ClipBoard) xml |
|||
EDIT(Text=xml, Right='<item', Right=5, GetPosition=a, Right='</item>', Left, GetPosition=z) |
|||
WRITE(Text=output) xml( a : z), $CRLF |
|||
i = 1 |
|||
1 EDIT(Text=xml, SetPosition=i, SePaRators='<>', Right='<price>', Word=1, Parse=price, GetPosition=i, ERror=99) |
|||
IF(i > 0) THEN |
|||
WRITE(Text=output, APPend) 'Price element = ', price, $CRLF |
|||
GOTO 1 ! HicEst does not have a "WHILE" |
|||
ENDIF |
|||
EDIT(Text=xml, SPR='<>', R='<name>', W=1, WordEnd=$CR, APpendTo=output, DO=999) |
|||
WRITE(ClipBoard) TRIM(output) </syntaxhighlight> |
|||
<syntaxhighlight lang="hicest"> upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
Price element = 14.50 |
|||
Price element = 23.99 |
|||
Price element = 4.95 |
|||
Price element = 3.56 |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</syntaxhighlight> |
|||
=={{header|Java}}== |
|||
<syntaxhighlight lang="java">import java.io.StringReader; |
|||
import javax.xml.parsers.DocumentBuilderFactory; |
|||
import javax.xml.xpath.XPath; |
|||
import javax.xml.xpath.XPathConstants; |
|||
import javax.xml.xpath.XPathFactory; |
|||
import org.w3c.dom.Document; |
|||
import org.w3c.dom.Node; |
|||
import org.w3c.dom.NodeList; |
|||
import org.xml.sax.InputSource; |
|||
public class XMLParser { |
|||
final static String xmlStr = |
|||
"<inventory title=\"OmniCorp Store #45x10^3\">" |
|||
+ " <section name=\"health\">" |
|||
+ " <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>" |
|||
+ " </section>" |
|||
+ " <section name=\"food\">" |
|||
+ " <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 priwater</description>" |
|||
+ " </item>" |
|||
+ " </section>" |
|||
+ "</inventory>"; |
|||
public static void main(String[] args) { |
|||
try { |
|||
Document doc = DocumentBuilderFactory.newInstance() |
|||
.newDocumentBuilder() |
|||
.parse(new InputSource(new StringReader(xmlStr))); |
|||
XPath xpath = XPathFactory.newInstance().newXPath(); |
|||
// 1 |
|||
System.out.println(((Node) xpath.evaluate( |
|||
"/inventory/section/item[1]", doc, XPathConstants.NODE)) |
|||
.getAttributes().getNamedItem("upc")); |
|||
// 2, 3 |
|||
NodeList nodes = (NodeList) xpath.evaluate( |
|||
"/inventory/section/item/price", doc, |
|||
XPathConstants.NODESET); |
|||
for (int i = 0; i < nodes.getLength(); i++) |
|||
System.out.println(nodes.item(i).getTextContent()); |
|||
} catch (Exception e) { |
|||
System.out.println("Error ocurred while parsing XML."); |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
{{works with|Firefox|2.0}} |
{{works with|Firefox|2.0}} |
||
<lang |
<syntaxhighlight 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 );</syntaxhighlight> |
|||
Although some browsers support XPath, working with XML is much easier with E4X. |
Although some browsers support XPath, working with XML is much easier with E4X. |
||
<lang |
<syntaxhighlight 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 );</syntaxhighlight> |
|||
=={{header|Julia}}== |
|||
Uses the LibExpat module for XML pathing. The exercise description is very |
|||
vague about output format, so this is varied in the solution below. The first |
|||
test prints the raw XML node, and the second and third are further processed. |
|||
<syntaxhighlight lang="julia">using LibExpat |
|||
xdoc = raw"""<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
""" |
|||
debracket(s) = replace(s, r".+\>(.+)\<.+" => s"\1") |
|||
etree = xp_parse(xdoc) |
|||
firstshow = LibExpat.find(etree, "//item")[1] |
|||
println("The first item's node XML entry is:\n", firstshow, "\n\n") |
|||
prices = LibExpat.find(etree, "//price") |
|||
println("Prices:") |
|||
for p in prices |
|||
println("\t", debracket(string(p))) |
|||
end |
|||
println("\n") |
|||
namearray = LibExpat.find(etree, "//name") |
|||
println("Array of names of items:\n\t", map(s -> debracket(string(s)), namearray)) |
|||
</syntaxhighlight>{{output}}<pre> |
|||
The first item's node XML entry is: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Prices: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Array of names of items: |
|||
["Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"] |
|||
</pre> |
|||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">// version 1.1.3 |
|||
import javax.xml.parsers.DocumentBuilderFactory |
|||
import org.xml.sax.InputSource |
|||
import java.io.StringReader |
|||
import javax.xml.xpath.XPathFactory |
|||
import javax.xml.xpath.XPathConstants |
|||
import org.w3c.dom.Node |
|||
import org.w3c.dom.NodeList |
|||
val xml = |
|||
""" |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
""" |
|||
fun main(args: Array<String>) { |
|||
val dbFactory = DocumentBuilderFactory.newInstance() |
|||
val dBuilder = dbFactory.newDocumentBuilder() |
|||
val xmlInput = InputSource(StringReader(xml)) |
|||
val doc = dBuilder.parse(xmlInput) |
|||
val xpFactory = XPathFactory.newInstance() |
|||
val xPath = xpFactory.newXPath() |
|||
val qNode = xPath.evaluate("/inventory/section/item[1]", doc, XPathConstants.NODE) as Node |
|||
val upc = qNode.attributes.getNamedItem("upc") |
|||
val stock = qNode.attributes.getNamedItem("stock") |
|||
println("For the first item : upc = ${upc.textContent} and stock = ${stock.textContent}") |
|||
val qNodes = xPath.evaluate("/inventory/section/item/price", doc, XPathConstants.NODESET) as NodeList |
|||
print("\nThe prices of each item are : ") |
|||
for (i in 0 until qNodes.length) print("${qNodes.item(i).textContent} ") |
|||
println() |
|||
val qNodes2 = xPath.evaluate("/inventory/section/item/name", doc, XPathConstants.NODESET) as NodeList |
|||
val names = Array<String>(qNodes2.length) { qNodes2.item(it).textContent } |
|||
println("\nThe names of each item are as follows :") |
|||
println(" ${names.joinToString("\n ")}") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
For the first item : upc = 123456789 and stock = 12 |
|||
The prices of each item are : 14.50 23.99 4.95 3.56 |
|||
The names of each item are as follows : |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
=={{header|Ksh}}== |
|||
<syntaxhighlight lang="ksh"> |
|||
#!/bin/ksh |
|||
# Perform XPath queries on a XML Document |
|||
# # Variables: |
|||
# |
|||
typeset -T Xml_t=( |
|||
typeset -h 'UPC' upc |
|||
typeset -i -h 'num in stock' stock=0 |
|||
typeset -h 'name' name |
|||
typeset -F2 -h 'price' price |
|||
typeset -h 'description' description |
|||
function init_item { |
|||
typeset key ; key="$1" |
|||
typeset val ; val="${2%\<\/${key}*}" |
|||
case ${key} in |
|||
upc) _.upc="${val//@(\D)/}" |
|||
;; |
|||
stock) _.stock="${val//@(\D)/}" |
|||
;; |
|||
name) _.name="${val%\<\/${key}*}" |
|||
;; |
|||
price) _.price="${val}" |
|||
;; |
|||
description) _.description=$(echo ${val}) |
|||
;; |
|||
esac |
|||
} |
|||
function prt_item { |
|||
print "upc= ${_.upc}" |
|||
print "stock= ${_.stock}" |
|||
print "name= ${_.name}" |
|||
print "price= ${_.price}" |
|||
print "description= ${_.description}" |
|||
} |
|||
) |
|||
# # Functions: |
|||
# |
|||
###### |
|||
# main # |
|||
###### |
|||
integer i=0 |
|||
typeset -a Item_t |
|||
buff=$(< xmldoc) # read xmldoc |
|||
item=${buff%%'</item>'*} ; buff=${.sh.match} |
|||
while [[ -n ${item} ]]; do |
|||
Xml_t Item_t[i] |
|||
item=${item#*'<item'} ; item=$(echo ${item}) |
|||
for word in ${item}; do |
|||
if [[ ${word} == *=* ]]; then |
|||
Item_t[i].init_item ${word%\=*} ${word#*\=} |
|||
else |
|||
if [[ ${word} == \<* ]]; then # Beginning |
|||
key=${word%%\>*} ; key=${key#*\<} |
|||
val=${word#*\>} |
|||
fi |
|||
[[ ${word} != \<* && ${word} != *\> ]] && val+=" ${word} " |
|||
if [[ ${word} == *\> ]]; then # End |
|||
val+=" ${word%\<${key}\>*}" |
|||
Item_t[i].init_item "${key}" "${val}" |
|||
fi |
|||
fi |
|||
done |
|||
(( i++ )) |
|||
item=${buff#*'</item>'} ; item=${item%%'</item>'*} ; buff=${.sh.match} |
|||
done |
|||
print "First Item element:" |
|||
Item_t[0].prt_item |
|||
typeset -a names |
|||
printf "\nList of prices:\n" |
|||
for ((i=0; i<${#Item_t[*]}-1; i++)); do |
|||
print ${Item_t[i].price} |
|||
names[i]=${Item_t[i].name} |
|||
done |
|||
printf "\nArray of names:\n" |
|||
for (( i=0; i<${#names[*]}; i++)); do |
|||
print "names[$i] = ${names[i]}" |
|||
done</syntaxhighlight> |
|||
{{out}}<pre> |
|||
First Item element: |
|||
upc= 123456789 |
|||
stock= 12 |
|||
name= Invisibility Cream |
|||
price= 14.50 |
|||
description= Makes you invisible |
|||
List of prices: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Array of names: |
|||
names[0] = Invisibility Cream |
|||
names[1] = Levitation Salve |
|||
names[2] = Blork and Freen Instameal |
|||
names[3] = Grob winglets</pre> |
|||
=={{header|Lasso}}== |
|||
Lasso has built in support for both XML handling and Xpaths |
|||
<syntaxhighlight lang="lasso">// makes extracting attribute values easier |
|||
define xml_attrmap(in::xml_namedNodeMap_attr) => { |
|||
local(out = map) |
|||
with attr in #in |
|||
do #out->insert(#attr->name = #attr->value) |
|||
return #out |
|||
} |
|||
local( |
|||
text = '<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
', |
|||
xml = xml(#text) |
|||
) |
|||
local( |
|||
items = #xml -> extract('//item'), |
|||
firstitem = #items -> first, |
|||
itemattr = xml_attrmap(#firstitem -> attributes), |
|||
newprices = array |
|||
) |
|||
'<strong>First item:</strong><br /> |
|||
UPC: ' |
|||
#itemattr -> find('upc') |
|||
' (stock: ' |
|||
#itemattr -> find('stock') |
|||
')<br />' |
|||
#firstitem -> extractone('name') -> nodevalue |
|||
' [' |
|||
#firstitem -> extractone('price') -> nodevalue |
|||
'] (' |
|||
#firstitem -> extractone('description') -> nodevalue |
|||
')<br /><br />' |
|||
with item in #items |
|||
let name = #item -> extractone('name') -> nodevalue |
|||
let price = #item -> extractone('price') -> nodevalue |
|||
do { |
|||
#newprices -> insert(#name + ': ' + (decimal(#price) * 1.10) -> asstring(-precision = 2) + ' (' + #price + ')') |
|||
} |
|||
'<strong>Adjusted prices:</strong><br />' |
|||
#newprices -> join('<br />') |
|||
'<br /><br />' |
|||
'<strong>Array with all names:</strong><br />' |
|||
#xml -> extract('//name') -> asstaticarray</syntaxhighlight> |
|||
Output: |
|||
<pre>First item: |
|||
UPC: 123456789 (stock: 12) |
|||
Invisibility Cream [14.50] (Makes you invisible) |
|||
Adjusted prices: |
|||
Invisibility Cream: 15.95 (14.50) |
|||
Levitation Salve: 26.39 (23.99) |
|||
Blork and Freen Instameal: 5.45 (4.95) |
|||
Grob winglets: 3.92 (3.56) |
|||
Array with all names: |
|||
staticarray(Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets)</pre> |
|||
=={{header|LiveCode}}== |
|||
Copy the xml in this task into a text field called "FieldXML" |
|||
<syntaxhighlight lang="livecode">put revXMLCreateTree(fld "FieldXML",true,true,false) into xmltree |
|||
// task 1 |
|||
put revXMLEvaluateXPath(xmltree,"//item[1]") into nodepath |
|||
put revXMLText(xmltree,nodepath,true) |
|||
// task 2 |
|||
put revXMLDataFromXPathQuery(xmltree,"//item/price",,comma) |
|||
// task 3 |
|||
put revXMLDataFromXPathQuery(xmltree,"//name") into namenodes |
|||
filter namenodes without empty |
|||
split namenodes using cr |
|||
put namenodes is an array</syntaxhighlight> |
|||
=={{header|Lua}}== |
|||
Requires LuaExpat |
|||
<syntaxhighlight lang="lua">require 'lxp' |
|||
data = [[<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory>]] |
|||
local first = true |
|||
local names, prices = {}, {} |
|||
p = lxp.new({StartElement = function (parser, name) |
|||
local a, b, c = parser:pos() --line, offset, pos |
|||
if name == 'item' and first then |
|||
print(data:match('.-</item>', c - b + 1)) |
|||
first = false |
|||
end |
|||
if name == 'name' then names[#names+1] = data:match('>(.-)<', c) end |
|||
if name == 'price' then prices[#prices+1] = data:match('>(.-)<', c) end |
|||
end}) |
|||
p:parse(data) |
|||
p:close() |
|||
print('Name: ', table.concat(names, ', ')) |
|||
print('Price: ', table.concat(prices, ', '))</syntaxhighlight> |
|||
Output:<pre> |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Name: Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets |
|||
Price: 14.50, 23.99, 4.95, 3.56 |
|||
</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">example = Import["test.txt", "XML"]; |
|||
Cases[example, XMLElement["item", _ , _] , Infinity] // First |
|||
Cases[example, XMLElement["price", _, List[n_]] -> n, Infinity] // Column |
|||
Cases[example, XMLElement["name", _, List[n_]] -> n, Infinity] // Column</syntaxhighlight> |
|||
{{out}} |
|||
<pre>XMLElement[item,{upc->123456789,stock->12}, |
|||
{XMLElement[name,{},{Invisibility Cream}],XMLElement[price,{},{14.50}],XMLElement[description,{},{Makes you invisible}]}] |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets</pre> |
|||
=={{header|NetRexx}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="netrexx">/* NetRexx */ |
|||
options replace format comments java symbols binary |
|||
import javax.xml.parsers. |
|||
import javax.xml.xpath. |
|||
import org.w3c.dom. |
|||
import org.w3c.dom.Node |
|||
import org.xml.sax. |
|||
xmlStr = '' - |
|||
|| '<inventory title="OmniCorp Store #45x10^3">' - |
|||
|| ' <section name="health">' - |
|||
|| ' <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>' - |
|||
|| ' </section>' - |
|||
|| ' <section name="food">' - |
|||
|| ' <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 priwater</description>' - |
|||
|| ' </item>' - |
|||
|| ' </section>' - |
|||
|| '</inventory>' |
|||
expr1 = '/inventory/section/item[1]' |
|||
expr2 = '/inventory/section/item/price' |
|||
expr3 = '/inventory/section/item/name' |
|||
attr1 = 'upc' |
|||
do |
|||
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xmlStr))) |
|||
xpath = XPathFactory.newInstance().newXPath() |
|||
-- Extract attribute from 1st item element |
|||
say expr1 |
|||
say " "(Node xpath.evaluate(expr1, doc, XPathConstants.NODE)).getAttributes().getNamedItem(attr1) |
|||
say |
|||
-- Extract and display all price elments |
|||
nodes = NodeList xpath.evaluate(expr2, doc, XPathConstants.NODESET) |
|||
say expr2 |
|||
loop i_ = 0 to nodes.getLength() - 1 |
|||
say Rexx(nodes.item(i_).getTextContent()).format(10, 2) |
|||
end i_ |
|||
say |
|||
-- Extract elements and store in an ArrayList |
|||
nameList = java.util.List |
|||
nameList = ArrayList() |
|||
nodes = NodeList xpath.evaluate(expr3, doc, XPathConstants.NODESET) |
|||
loop i_ = 0 to nodes.getLength() - 1 |
|||
nameList.add(nodes.item(i_).getTextContent()) |
|||
end i_ |
|||
-- display contents of ArrayList |
|||
say expr3 |
|||
loop n_ = 0 to nameList.size() - 1 |
|||
say " "nameList.get(n_) |
|||
end n_ |
|||
say |
|||
catch ex = Exception |
|||
ex.printStackTrace() |
|||
end |
|||
return |
|||
</syntaxhighlight> |
|||
'''Output:''' |
|||
<pre> |
|||
/inventory/section/item[1] |
|||
upc="123456789" |
|||
/inventory/section/item/price |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
/inventory/section/item/name |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
=={{header|Nim}}== |
|||
{{libheader|libxml2}} |
|||
Nim standard library provides several modules to process XML, but none to process XPath requests. There is no third party library to do that either. |
|||
So we provide here a solution which uses the C "libxml2" library. Nim allows to interface with C with a great flexibility. Declaring the external functions is quite easy. The major part of the work consists to declare the data types. In "libxml2" there are a lot of structures and we have translated only what is needed to solve the task (or actually a bit more). |
|||
For the first request, we use <code>//section[1]/item[1]</code> instead of <code>//item[1]</code> (this is also what the Python version does). The latter request works but it returns the first element in each section which doesn’t seem to be what is expected. |
|||
<syntaxhighlight lang="nim">import sequtils, strutils |
|||
const LibXml = "libxml2.so" |
|||
type |
|||
XmlDocPtr = pointer |
|||
XmlXPathContextPtr = pointer |
|||
XmlElementKind = enum |
|||
xmlElementNode = 1 |
|||
xmlAttributeNode = 2 |
|||
xmlTextNode = 3 |
|||
xmlCdataSectionNode = 4 |
|||
xmlEntityRefNode = 5 |
|||
xmlEntityNode = 6 |
|||
xmlPiNode = 7 |
|||
xmlCommentNode = 8 |
|||
xmlDocumentNode = 9 |
|||
xmlDocumentTypeNode = 10 |
|||
xmlDocumentFragNode = 11 |
|||
xmlNotationNode = 12 |
|||
xmlHtmlDocumentNode = 13 |
|||
xmlDtdNode = 14 |
|||
xmlElementDecl = 15 |
|||
xmlAttributeDecl = 16 |
|||
xmlEntityDecl = 17 |
|||
xmlNamespaceDecl = 18 |
|||
xmlXincludeStart = 19 |
|||
xmlXincludeEnd = 20 |
|||
XmlNsKind = XmlElementKind |
|||
XmlNsPtr = ptr XmlNs |
|||
XmlNs = object |
|||
next: XmlNsPtr |
|||
kind: XmlNsKind |
|||
href: cstring |
|||
prefix: cstring |
|||
private: pointer |
|||
context: XmlDocPtr |
|||
XmlAttrPtr = pointer |
|||
XmlNodePtr = ptr XmlNode |
|||
XmlNode = object |
|||
private: pointer |
|||
kind: XmlElementKind |
|||
name: cstring |
|||
children: XmlNodePtr |
|||
last: XmlNodePtr |
|||
parent: XmlNodePtr |
|||
next: XmlNodePtr |
|||
prev: XmlNodePtr |
|||
doc: XmlDocPtr |
|||
ns: XmlNsPtr |
|||
content: cstring |
|||
properties: XmlAttrPtr |
|||
nsDef: XmlNsPtr |
|||
psvi: pointer |
|||
line: cushort |
|||
extra: cushort |
|||
XmlNodeSetPtr = ptr XmlNodeSet |
|||
XmlNodeSet = object |
|||
nodeNr: cint |
|||
nodeMax: cint |
|||
nodeTab: ptr UncheckedArray[XmlNodePtr] |
|||
XmlPathObjectKind = enum |
|||
xpathUndefined |
|||
xpathNodeset |
|||
xpathBoolean |
|||
xpathNumber |
|||
xpathString |
|||
xpathPoint |
|||
xpathRange |
|||
xpathLocationset |
|||
xpathUsers |
|||
xpathXsltTree |
|||
XmlXPathObjectPtr = ptr XmlXPathObject |
|||
XmlXPathObject = object |
|||
kind: XmlPathObjectKind |
|||
nodeSetVal: XmlNodeSetPtr |
|||
boolVal: cint |
|||
floatVal: cdouble |
|||
stringVal: cstring |
|||
user: pointer |
|||
index: cint |
|||
user2: pointer |
|||
index2: cint |
|||
XmlSaveCtxtPtr = pointer |
|||
XmlBufferPtr = pointer |
|||
# Declaration of needed "libxml2" procedures. |
|||
proc xmlParseFile(docName: cstring): XmlDocPtr |
|||
{.cdecl, dynlib: LibXml, importc: "xmlParseFile".} |
|||
proc xmlXPathNewContext(doc: XmlDocPtr): XmlXPathContextPtr |
|||
{.cdecl, dynlib: LibXml, importc: "xmlXPathNewContext".} |
|||
proc xmlXPathEvalExpression(str: cstring; ctxt: XmlXPathContextPtr): XmlXPathObjectPtr |
|||
{.cdecl, dynlib: LibXml, importc: "xmlXPathEvalExpression".} |
|||
proc xmlXPathFreeContext(ctxt: XmlXPathContextPtr) |
|||
{.cdecl, dynlib: LibXml, importc: "xmlXPathFreeContext".} |
|||
proc xmlXPathFreeObject(obj: XmlXPathObjectPtr) |
|||
{.cdecl, dynlib: LibXml, importc: "xmlXPathFreeObject".} |
|||
proc xmlSaveToBuffer(vuffer: XmlBufferPtr; encoding: cstring; options: cint): XmlSaveCtxtPtr |
|||
{.cdecl, dynlib: LibXml, importc: "xmlSaveToBuffer".} |
|||
proc xmlBufferCreate(): XmlBufferPtr |
|||
{.cdecl, dynlib: LibXml, importc: "xmlBufferCreate".} |
|||
proc xmlBufferFree(buf: XmlBufferPtr) |
|||
{.cdecl, dynlib: LibXml, importc: "xmlBufferCreate".} |
|||
proc xmlBufferContent(buf: XmlBufferPtr): cstring |
|||
{.cdecl, dynlib: LibXml, importc: "xmlBufferContent".} |
|||
proc xmlSaveTree(ctxt: XmlSaveCtxtPtr; cur: XmlNodePtr): clong |
|||
{.cdecl, dynlib: LibXml, importc: "xmlSaveTree".} |
|||
proc xmlSaveClose(ctxt: XmlSaveCtxtPtr) |
|||
{.cdecl, dynlib: LibXml, importc: "xmlSaveClose".} |
|||
proc `$`(node: XmlNodePtr): string = |
|||
## Return the representation of a node. |
|||
let buffer = xmlBufferCreate() |
|||
let saveContext = xmlSaveToBuffer(buffer, nil, 0) |
|||
discard saveContext.xmlSaveTree(node) |
|||
saveContext.xmlSaveClose() |
|||
result = $buffer.xmlBufferContent() |
|||
xmlBufferFree(buffer) |
|||
iterator nodes(xpath: string; context: XmlXPathContextPtr): XmlNodePtr = |
|||
## Yield the nodes which fit the XPath request. |
|||
let xpathObj = xmlXPathEvalExpression(xpath, context) |
|||
if xpathObj.isNil: |
|||
quit "Failed to evaluate XPath: " & xpath, QuitFailure |
|||
assert xpathObj.kind == xpathNodeset |
|||
let nodeSet = xpathObj.nodeSetVal |
|||
if not nodeSet.isNil: |
|||
for i in 0..<nodeSet.nodeNr: |
|||
yield nodeSet.nodeTab[i] |
|||
xmlXPathFreeObject(xpathObj) |
|||
# Load and parse XML file. |
|||
let doc = xmlParseFile("xpath_test.xml") |
|||
if doc.isNil: |
|||
quit "Unable to load and parse document", QuitFailure |
|||
# Create an XPath context. |
|||
let context = xmlXPathNewContext(doc) |
|||
if context.isNil: |
|||
quit "Failed to create XPath context", QuitFailure |
|||
var xpath = "//section[1]/item[1]" |
|||
echo "Request $#:".format(xpath) |
|||
for node in nodes(xpath, context): |
|||
echo node |
|||
echo() |
|||
xpath = "//price/text()" |
|||
echo "Request $#:".format(xpath) |
|||
for node in nodes(xpath, context): |
|||
echo node.content |
|||
echo() |
|||
xpath = "//name" |
|||
echo "Request $#:".format(xpath) |
|||
let names = toSeq(nodes(xpath, context)).mapIt(it.children.content) |
|||
echo names |
|||
xmlXPathFreeContext(context)</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Request //section[1]/item[1]: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
Request //price/text(): |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Request //name: |
|||
@["Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"]</pre> |
|||
=={{header|Objeck}}== |
|||
XPath is used to fetch element tags. |
|||
<syntaxhighlight lang="objeck"> |
|||
use XML; |
|||
bundle Default { |
|||
class Test { |
|||
function : Main(args : String[]) ~ Nil { |
|||
in := String->New(); |
|||
in->Append("<inventory title=\"OmniCorp Store #45x10^3\">"); |
|||
in->Append("<section name=\"health\">"); |
|||
in->Append("<item upc=\"123456789\" stock=\"12\">"); |
|||
in->Append("<name>Invisibility Cream</name>"); |
|||
in->Append("<price>14.50</price>"); |
|||
in->Append("<description>Makes you invisible</description>"); |
|||
in->Append("</item>"); |
|||
in->Append("<item upc=\"445322344\" stock=\"18\">"); |
|||
in->Append("<name>Levitation Salve</name>"); |
|||
in->Append("<price>23.99</price>"); |
|||
in->Append("<description>Levitate yourself for up to 3 hours per application</description>"); |
|||
in->Append("</item>"); |
|||
in->Append("</section>"); |
|||
in->Append("<section name=\"food\">"); |
|||
in->Append("<item upc=\"485672034\" stock=\"653\">"); |
|||
in->Append("<name>Blork and Freen Instameal</name>"); |
|||
in->Append("<price>4.95</price>"); |
|||
in->Append("<description>A tasty meal in a tablet; just add water</description>"); |
|||
in->Append("</item>"); |
|||
in->Append("<item upc=\"132957764\" stock=\"44\">"); |
|||
in->Append("<name>Grob winglets</name>"); |
|||
in->Append("<price>3.56</price>"); |
|||
in->Append("<description>Tender winglets of Grob. Just add water</description>"); |
|||
in->Append("</item>"); |
|||
in->Append("</section>"); |
|||
in->Append("</inventory>"); |
|||
parser := XmlParser->New(in); |
|||
if(parser->Parse()) { |
|||
# get first item |
|||
results := parser->FindElements("//inventory/section[1]/item[1]"); |
|||
if(results <> Nil) { |
|||
IO.Console->Instance()->Print("items: ")->PrintLine(results->Size()); |
|||
}; |
|||
# get all prices |
|||
results := parser->FindElements("//inventory/section/item/price"); |
|||
if(results <> Nil) { |
|||
each(i : results) { |
|||
element := results->Get(i)->As(XMLElement); |
|||
element->GetContent()->PrintLine(); |
|||
}; |
|||
}; |
|||
# get names |
|||
results := parser->FindElements("//inventory/section/item/name"); |
|||
if(results <> Nil) { |
|||
IO.Console->Instance()->Print("names: ")->PrintLine(results->Size()); |
|||
}; |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Oz}}== |
|||
We implement a small subset of XPath for this task: |
|||
<syntaxhighlight lang="oz">declare |
|||
[XMLParser] = {Module.link ['x-oz://system/xml/Parser.ozf']} |
|||
proc {Main Data} |
|||
Parser = {New XMLParser.parser init} |
|||
[Doc] = {Parser parseVS(Data $)} |
|||
FirstItem = {XPath Doc [inventory section item]}.1 |
|||
Prices = {XPath Doc [inventory section item price Text]} |
|||
Names = {XPath Doc [inventory section item name]} |
|||
in |
|||
{ForAll Prices System.showInfo} |
|||
end |
|||
%% |
|||
%% Emulation of some XPath functionality: |
|||
%% |
|||
fun {XPath Doc Path} |
|||
P|Pr = Path |
|||
in |
|||
Doc.name = P %% assert |
|||
{FoldL Pr XPathStep [Doc]} |
|||
end |
|||
fun {XPathStep Elements P} |
|||
if {IsProcedure P} then |
|||
{Map Elements P} |
|||
else |
|||
{FilteredChildren Elements P} |
|||
end |
|||
end |
|||
%% A flat list of all Type-children of all Elements. |
|||
fun {FilteredChildren Elements Type} |
|||
{Flatten |
|||
{Map Elements |
|||
fun {$ E} |
|||
{Filter E.children |
|||
fun {$ X} |
|||
case X of element(name:!Type ...) then true |
|||
else false |
|||
end |
|||
end} |
|||
end}} |
|||
end |
|||
%% PCDATA of an element as a ByteString |
|||
fun {Text Element} |
|||
Texts = for Child in Element.children collect:C do |
|||
case Child of text(data:BS ...) then {C BS} end |
|||
end |
|||
in |
|||
{FoldR Texts ByteString.append {ByteString.make nil}} |
|||
end |
|||
Data = |
|||
"<inventory title=\"OmniCorp Store #45x10^3\">" |
|||
#" <section name=\"health\">" |
|||
#" <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>" |
|||
#" </section>" |
|||
#" <section name=\"food\">" |
|||
#" <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>" |
|||
#" </section>" |
|||
#"</inventory>" |
|||
in |
|||
{Main Data}</syntaxhighlight> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{libheader|XML::XPath}} |
{{libheader|XML::XPath}} |
||
<lang |
<syntaxhighlight 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;</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
Phix has no direct support for XPath, but achieving the requirements using the standard xml_parse() is not exactly difficult. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">/</span><span style="color: #000000;">xml</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">xml_txt</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""" |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
"""</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000080;font-style:italic;">-- or, of course, xml_txt = get_text("input.xml")</span> |
|||
<span style="color: #000000;">xml</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">xml_parse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xml_txt</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">sections</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">xml_get_nodes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xml</span><span style="color: #0000FF;">[</span><span style="color: #000000;">XML_CONTENTS</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"section"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">item1</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> |
|||
<span style="color: #000000;">prices</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> |
|||
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">items</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">xml_get_nodes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">s</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"item"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">item1</span><span style="color: #0000FF;">={}</span> <span style="color: #008080;">then</span> <span style="color: #000000;">item1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">items</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">prices</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">prices</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xml_get_nodes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"price"</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">XML_CONTENTS</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xml_get_nodes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">items</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"name"</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">XML_CONTENTS</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"===item[1]===\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tmp</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">xml_new_doc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">item1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">xml_sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tmp</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"===prices===\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">prices</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"===names===\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Maxlen</span><span style="color: #0000FF;">,</span><span style="color: #000000;">90</span><span style="color: #0000FF;">})</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
<pre> |
|||
===item[1]=== |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
===prices=== |
|||
{`14.50`, `23.99`, `4.95`, `3.56`} |
|||
===names=== |
|||
{`Invisibility Cream`, `Levitation Salve`, `Blork and Freen Instameal`, `Grob winglets`} |
|||
</pre> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
<syntaxhighlight lang="php"><?php |
|||
<lang php> |
|||
//PHP5 only example due to changes in XML extensions between version 4 and 5 (Tested on PHP5.2.0) |
|||
<?php |
|||
$doc = DOMDocument::loadXML('<inventory title="OmniCorp Store #45x10^3">...</inventory>'); |
|||
//PHP5 only example due to changes in XML extensions between version 4 and 5 (Tested on PHP5.2.0) |
|||
$doc = DOMDocument:: |
//Load from file instead with $doc = DOMDocument::load('filename'); |
||
$xpath = new DOMXPath($doc); |
|||
//Load from file instead with $doc = DOMDocument::load('filename'); |
|||
/* |
|||
$xpath = new DOMXPath($doc); |
|||
1st Task: Retrieve the first "item" element |
|||
/* |
|||
*/ |
|||
1st Task: Retrieve the first "item" element |
|||
$nodelist = $xpath->query('//item'); |
|||
*/ |
|||
$result = $nodelist->item(0); |
|||
/* |
|||
$result = $nodelist->item(0); |
|||
2nd task: Perform an action on each "price" element (print it out) |
|||
/* |
|||
*/ |
|||
2nd task: Perform an action on each "price" element (print it out) |
|||
$nodelist = $xpath->query('//price'); |
|||
*/ |
|||
for($i = 0; $i < $nodelist->length; $i++) |
|||
$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"; |
|||
//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 |
|||
/* |
|||
*/ |
|||
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 |
|||
$nodelist = $xpath->query('//name'); |
|||
$result = array(); |
|||
//our array to hold all the name elements, though in practice you'd probably not need to do this and simply use the DOMNodeList |
|||
//a different way of iterating through the DOMNodeList |
|||
$result = array(); |
|||
foreach($nodelist as $node) |
|||
//a different way of iterating through the DOMNodeList |
|||
{ |
|||
foreach($nodelist as $node) |
|||
$result[] = $node; |
|||
{ |
|||
}</syntaxhighlight> |
|||
$result[] = $node; |
|||
} |
|||
=={{header|PicoLisp}}== |
|||
</lang> |
|||
<syntaxhighlight lang="picolisp">(load "@lib/xm.l") |
|||
(let Sections (body (in "file.xml" (xml))) |
|||
(pretty (car (body (car Sections)))) |
|||
(prinl) |
|||
(for S Sections |
|||
(for L (body S) |
|||
(prinl (car (body L 'price))) ) ) |
|||
(make |
|||
(for S Sections |
|||
(for L (body S) |
|||
(link (car (body L 'name))) ) ) ) )</syntaxhighlight> |
|||
Output: |
|||
<pre>(item |
|||
((upc . "123456789") (stock . "12")) |
|||
(name NIL "Invisibility Cream") |
|||
(price NIL "14.50") |
|||
(description NIL "Makes you invisible") ) |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
-> ("Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets")</pre> |
|||
=={{header|PowerShell}}== |
|||
Cast the <code>$document</code> string as <code>[xml]</code> and you have access to .NET methods affecting XML. |
|||
<syntaxhighlight lang="powershell"> |
|||
$document = [xml]@' |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
'@ |
|||
$query = "/inventory/section/item" |
|||
$items = $document.SelectNodes($query) |
|||
</syntaxhighlight> |
|||
The first item: |
|||
<syntaxhighlight lang="powershell"> |
|||
$items[0] |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
upc : 123456789 |
|||
stock : 12 |
|||
name : Invisibility Cream |
|||
price : 14.50 |
|||
description : Makes you invisible |
|||
</pre> |
|||
Get some useful information: |
|||
<syntaxhighlight lang="powershell"> |
|||
$namesAndPrices = $items | Select-Object -Property name, price |
|||
$namesAndPrices |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
name price |
|||
---- ----- |
|||
Invisibility Cream 14.50 |
|||
Levitation Salve 23.99 |
|||
Blork and Freen Instameal 4.95 |
|||
Grob winglets 3.56 |
|||
</pre> |
|||
Here are the prices: |
|||
<syntaxhighlight lang="powershell"> |
|||
$items.price |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
</pre> |
|||
Here are the names: |
|||
<syntaxhighlight lang="powershell"> |
|||
$items.name |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
<syntaxhighlight lang="python"># Python has basic xml parsing built in |
|||
<lang python> |
|||
# Python has basic xml parsing built in |
|||
from xml.dom import minidom |
from xml.dom import minidom |
||
xmlfile = file("test3.xml") # load xml document from file |
xmlfile = file("test3.xml") # load xml document from file |
||
xmldoc = |
xmldoc = minidom.parse(xmlfile).documentElement # parse from file stream or... |
||
xmldoc = |
xmldoc = minidom.parseString("<inventory title="OmniCorp Store #45x10^3">...</inventory>").documentElement # alternatively, parse a string |
||
# 1st Task: Retrieve the first "item" element |
# 1st Task: Retrieve the first "item" element |
||
Line 390: | Line 3,229: | ||
# 3rd Task: Get an array of all the "name" elements |
# 3rd Task: Get an array of all the "name" elements |
||
namesArray = xmldoc.getElementsByTagName("name") |
namesArray = xmldoc.getElementsByTagName("name")</syntaxhighlight> |
||
In Python 2.5+ you can use ElementTree's limited XPath support |
|||
</lang> |
|||
<syntaxhighlight lang="python"> |
|||
import xml.etree.ElementTree as ET |
|||
xml = open('inventory.xml').read() |
|||
doc = ET.fromstring(xml) |
|||
doc = ET.parse('inventory.xml') # or load it directly |
|||
# Note, ElementTree's root is the top level element. So you need ".//" to really start searching from top |
|||
# Return first Item |
|||
item1 = doc.find("section/item") # or ".//item" |
|||
# Print each price |
|||
for p in doc.findall("section/item/price"): # or ".//price" |
|||
print "{0:0.2f}".format(float(p.text)) # could raise exception on missing text or invalid float() conversion |
|||
# list of names |
|||
names = doc.findall("section/item/name") # or ".//name"</syntaxhighlight> |
|||
Or, you can install the <tt>lxml</tt> package and get full XPath support |
|||
<syntaxhighlight lang="python"> |
|||
from lxml import etree |
|||
xml = open('inventory.xml').read() |
|||
doc = etree.fromstring(xml) |
|||
doc = etree.parse('inventory.xml') # or load it directly |
|||
# Return first item |
|||
item1 = doc.xpath("//section[1]/item[1]") |
|||
# Print each price |
|||
for p in doc.xpath("//price"): |
|||
print "{0:0.2f}".format(float(p.text)) # could raise exception on missing text or invalid float() conversion |
|||
names = doc.xpath("//name") # list of names</syntaxhighlight> |
|||
=={{header|R}}== |
=={{header|R}}== |
||
{{libheader|XML (R)}} |
{{libheader|XML (R)}} |
||
<syntaxhighlight lang="r"> |
|||
<lang R> |
|||
## Require the XML package you can download from http://www.omegahat.org/RSXML/ |
|||
library("XML") |
library("XML") |
||
doc <- xmlInternalTreeParse("test3.xml") |
doc <- xmlInternalTreeParse("test3.xml") |
||
# 1st Task: Retrieve the first "item" element |
|||
(firstItemElement <- getNodeSet(doc, "//item")[[1]]) |
|||
# 2nd task: Perform an action on each "price" element (print it out) |
|||
prices <- sapply(getNodeSet(doc, "//price"), xmlValue) |
|||
for(i in 1:length(prices)) print(prices[i]) |
|||
# 3rd Task: Get an array of all the "name" elements |
|||
(namesArray <- sapply(getNodeSet(doc, "//name"), xmlValue)) |
|||
# Retrieve the first "item" element |
|||
</lang> |
|||
getNodeSet(doc, "//item")[[1]] |
|||
# Perform an action on each "price" element |
|||
sapply(getNodeSet(doc, "//price"), xmlValue) |
|||
# Get an array of all the "name" elements |
|||
sapply(getNodeSet(doc, "//name"), xmlValue) |
|||
</syntaxhighlight> |
|||
=={{header|Racket}}== |
|||
<syntaxhighlight lang="racket"> |
|||
#lang at-exp racket |
|||
(define input @~a{ |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory>}) |
|||
(require xml xml/path) |
|||
(define data (xml->xexpr |
|||
((eliminate-whitespace '(inventory section item)) |
|||
(read-xml/element (open-input-string input))))) |
|||
;; Retrieve the first "item" element |
|||
(displayln (xexpr->string (se-path* '(item) data))) |
|||
;; => <name>Invisibility Cream</name> |
|||
;; Perform an action on each "price" element (print it out) |
|||
(printf "Prices: ~a\n" (string-join (se-path*/list '(item price) data) ", ")) |
|||
;; => Prices: 14.50, 23.99, 4.95, 3.56 |
|||
;; Get an array of all the "name" elements |
|||
(se-path*/list '(item name) data) |
|||
;; => '("Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets") |
|||
</syntaxhighlight> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>use XML::XPath; |
|||
my $XML = XML::XPath.new(xml => q:to/END/); |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
END |
|||
put "First item:\n", $XML.find('//item[1]')[0]; |
|||
put "\nPrice elements:"; |
|||
.contents.put for $XML.find('//price').List; |
|||
put "\nName elements:\n", $XML.find('//name')».contents.join: ', ';</syntaxhighlight> |
|||
{{out}} |
|||
<pre>First item: |
|||
<item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> |
|||
Price elements: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
Name elements: |
|||
Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets</pre> |
|||
=={{header|Rascal}}== |
|||
<syntaxhighlight lang="rascal">import lang::xml::DOM; |
|||
import Prelude; |
|||
public void get_first_item(loc a){ |
|||
D = parseXMLDOM(readFile(a)); |
|||
top-down-break visit(D){ |
|||
case E:element(_,"item",_): return println(xmlPretty(E)); |
|||
}; |
|||
} |
|||
public void print_prices(loc a){ |
|||
D = parseXMLDOM(readFile(a)); |
|||
for(/element(_,"price",[charData(/str p)]) := D) |
|||
println(p); |
|||
} |
|||
public list[str] get_names(loc a){ |
|||
D = parseXMLDOM(readFile(a)); |
|||
L = []; |
|||
for(/element(_,"name",[charData(/str n)]) := D) |
|||
L += n; |
|||
return L; |
|||
}</syntaxhighlight> |
|||
Example output: |
|||
<syntaxhighlight lang="rascal">rascal>get_first_item(|file:///Users/.../Desktop/xmlpath.xml|) |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<item stock="12" upc="123456789"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
ok |
|||
rascal>print_prices(|file:///Users/.../Desktop/xmlpath.xml|) |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
ok |
|||
rascal>get_names(|file:///Users/.../Desktop/xmlpath.xml|) |
|||
list[str]: ["Invisibility Cream","Levitation Salve","Blork and Freen Instameal","Grob winglets"]</syntaxhighlight> |
|||
=={{header|REXX}}== |
|||
===hard coded parsing=== |
|||
<syntaxhighlight lang="rexx">/*REXX program to parse various queries on an XML document (from a file). */ |
|||
iFID='XPATH.XML' /*name of the input XML file (doc). */ |
|||
$= /*string will contain the file's text. */ |
|||
do j=1 while lines(iFID)\==0 /*read the entire file into a string. */ |
|||
$=$ linein(iFID) /*append the line to the $ string. */ |
|||
end /*j*/ |
|||
/* [↓] show 1st ITEM in the document*/ |
|||
parse var $ '<item ' item "</item>" |
|||
say center('first item:',length(space(item)),'─') /*display a nice header.*/ |
|||
say space(item) |
|||
/* [↓] show all PRICES in the document*/ |
|||
prices= /*nullify the list and add/append to it*/ |
|||
$$=$ /*start with a fresh copy of document. */ |
|||
do until $$='' /* [↓] keep parsing string until done.*/ |
|||
parse var $$ '<price>' price '</price>' $$ |
|||
prices=prices price /*add/append the price to the list. */ |
|||
end /*until*/ |
|||
say |
|||
say center('prices:',length(space(prices)),'─') /*display a nice header.*/ |
|||
say space(prices) |
|||
/* [↓] show all NAMES in the document*/ |
|||
names.= /*nullify the list and add/append to it*/ |
|||
L=length(' names: ') /*maximum length of any one list name. */ |
|||
$$=$ /*start with a fresh copy of document. */ |
|||
do #=1 until $$='' /* [↓] keep parsing string until done.*/ |
|||
parse var $$ '<name>' names.# '</name>' $$ |
|||
L=max(L,length(names.#)) /*L: is used to find the widest name. */ |
|||
end /*#*/ |
|||
names.0=#-1; say /*adjust the number of names (DO loop).*/ |
|||
say center('names:',L,'─') /*display a nicely formatted header. */ |
|||
do k=1 for names.0 /*display all the names in the list. */ |
|||
say names.k /*display a name from the NAMES list.*/ |
|||
end /*k*/ |
|||
/*stick a fork in it, we're all done. */</syntaxhighlight> |
|||
'''output''' |
|||
<pre> |
|||
──────────────────────────────────────────────────────────first item:────────────────────────────────────────────────────────── |
|||
upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> |
|||
───────prices:─────── |
|||
14.50 23.99 4.95 3.56 |
|||
─────────names:────────── |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
===generic parsing=== |
|||
<syntaxhighlight lang="rexx">/*REXX program to parse various queries on an XML document (from a file). */ |
|||
iFID='XPATH.XML' /*name of the input XML file (doc). */ |
|||
$= /*string will contain the file's text. */ |
|||
do j=1 while lines(iFID)\==0 /*read the entire file into a string. */ |
|||
$=$ linein(iFID) /*append the line to the $ string. */ |
|||
end /*j*/ |
|||
/* [↓] display 1st ITEM in document. */ |
|||
call parser 'item', 0 /*go and parse the all the ITEMs. */ |
|||
say center('first item:',@L.1,'─') /*display a nicely formatted header. */ |
|||
say @.1; say /*display the first ITEM found. */ |
|||
call parser 'price' /*go and parse all the PRICEs. */ |
|||
say center('prices:',length(@@@),'─') /*display a nicely formatted header. */ |
|||
say @@@; say /*display a list of all the prices. */ |
|||
call parser 'name' |
|||
say center('names:',@L,'─') /*display a nicely formatted header. */ |
|||
do k=1 for # /*display all the names in the list. */ |
|||
say @.k /*display a name from the NAMES list.*/ |
|||
end /*k*/ |
|||
exit /*stick a fork in it, we're all done. */ |
|||
/*────────────────────────────────────────────────────────────────────────────*/ |
|||
parser: parse arg yy,tail,,@. @@. @@@; $$=$; @L=9; yb='<'yy; ye='</'yy">" |
|||
tail=word(tail 1, 1) /*use a tail ">" or not?*/ |
|||
do #=1 until $$='' /*parse complete XML doc. */ |
|||
if tail then parse var $$ (yb) '>' @@.# (ye) $$ /*find meat.*/ |
|||
else parse var $$ (yb) @@.# (ye) $$ /* " " */ |
|||
@.#=space(@@.#); @@@=space(@@@ @.#) /*shrink; @@@=list of YY.*/ |
|||
@L.#=length(@.#); @L=max(@L,@L.#) /*length; maximum length. */ |
|||
end /*#*/ |
|||
#=#-1 /*adjust # of thing found.*/ |
|||
return</syntaxhighlight> |
|||
'''output''' is the same as the 1<sup>st</sup> version. |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
{{libheader|REXML}} |
{{libheader|REXML}} |
||
<lang |
<syntaxhighlight 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" )</syntaxhighlight> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
The problem description isn't clear on whether what |
|||
is wanted is the element or the text. Because of that, |
|||
I'm doing both except for the first problem. |
|||
The |
The code is entered in to Scala's REPL, to |
||
better show the results. |
better show the results. |
||
< |
<syntaxhighlight lang="scala"> |
||
scala> val xml |
scala> val xml: scala.xml.Elem = |
||
| <inventory title="OmniCorp Store #45x10^3"> |
|||
| <section name="health"> |
| <section name="health"> |
||
| <item upc="123456789" stock="12"> |
| <item upc="123456789" stock="12"> |
||
Line 463: | Line 3,574: | ||
| </section> |
| </section> |
||
| </inventory> |
| </inventory> |
||
xml: scala.xml.Elem = |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
scala> val firstItem = xml \\ "item" |
scala> val firstItem = xml \\ "item" take 1 |
||
firstItem: scala.xml. |
firstItem: scala.xml.NodeSeq = |
||
<item upc="123456789" stock="12"> |
NodeSeq(<item upc="123456789" stock="12"> |
||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item>) |
|||
scala> xml \\ "price" foreach println |
scala> xml \\ "price" map (_.text) foreach println |
||
<price>14.50</price> |
|||
<price>23.99</price> |
|||
<price>4.95</price> |
|||
<price>3.56</price> |
|||
scala> xml \\ "price" map (_ text) foreach println |
|||
14.50 |
14.50 |
||
23.99 |
23.99 |
||
Line 511: | Line 3,589: | ||
3.56 |
3.56 |
||
scala> val |
scala> val names = (xml \\ "name").toArray |
||
names: Array[scala.xml.Node] = Array(<name>Invisibility Cream</name>, <name>Levitation Salve</name>, <name>Blork and Freen Instameal</name>, <name>Grob winglets</name>)</syntaxhighlight> |
|||
Freen Instameal</name>, <name>Grob winglets</name>) |
|||
=={{header|SenseTalk}}== |
|||
<syntaxhighlight lang="sensetalk">Set XMLSource to {{ |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
}} |
|||
put node "//item[1]" of XMLSource |
|||
put node "//price/text()" of XMLSource |
|||
put all nodes "//name" of XMLSource</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
14.50 |
|||
(<name>Invisibility Cream</name>,<name>Levitation Salve</name>,<name>Blork and Freen Instameal</name>,<name>Grob winglets</name>) |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
{{trans|Perl}} |
|||
<syntaxhighlight lang="ruby">require('XML::XPath'); |
|||
var x = %s'XML::XPath'.new(ARGF.slurp); |
|||
[x.findnodes('//item[1]')][0]; |
|||
say [x.findnodes('//price')].map{x.getNodeText(_)}; |
|||
[x.findnodes('//name')];</syntaxhighlight> |
|||
{{out}} |
|||
scala> val values = xml \\ "name" map (_ text) toArray |
|||
<pre> |
|||
values: Array[String] = Array(Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets) |
|||
[14.5, 23.99, 4.95, 3.56] |
|||
</lang> |
|||
</pre> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
{{libheader|tDOM}} |
{{libheader|tDOM}} |
||
< |
<syntaxhighlight lang="tcl"># assume $xml holds the XML data |
||
package require tdom |
package require tdom |
||
set doc [dom parse $xml] |
set doc [dom parse $xml] |
||
Line 534: | Line 3,667: | ||
foreach node [$root selectNodes //price] { |
foreach node [$root selectNodes //price] { |
||
puts [$node text] |
puts [$node text] |
||
}</ |
}</syntaxhighlight> |
||
=={{header|TUSCRIPT}}== |
|||
<syntaxhighlight lang="tuscript"> |
|||
$$ MODE TUSCRIPT,{} |
|||
MODE DATA |
|||
$$ XML=* |
|||
<inventory title="OmniCorp Store #45x10³"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
$$ MODE TUSCRIPT |
|||
FILE = "test.xml" |
|||
ERROR/STOP CREATE (file,fdf-o,-std-) |
|||
FILE/ERASE/UTF8 $FILE = xml |
|||
BUILD S_TABLE beg=":<item*>:<name>:<price>:" |
|||
BUILD S_TABLE end=":</item>:</name>:</price>:" |
|||
BUILD S_TABLE modifiedbeg=":<name>:<price>:" |
|||
BUILD S_TABLE modifiedend=":</name>:</price>:" |
|||
firstitem=names="",countitem=0 |
|||
ACCESS q: READ/STREAM/UTF8 $FILE s,a/beg+t+e/end |
|||
LOOP |
|||
READ/EXIT q |
|||
IF (a=="<name>") names=APPEND(names,t) |
|||
IF (a=="<price>") PRINT t |
|||
IF (a.sw."<item") countitem=1 |
|||
IF (countitem==1) THEN |
|||
firstitem=CONCAT(firstitem,a) |
|||
firstitem=CONCAT(firstitem,t) |
|||
firstitem=CONCAT(firstitem,e) |
|||
IF (e=="</item>") THEN |
|||
COUNTITEM=0 |
|||
MODIFY ACCESS q s_TABLE modifiedbeg,-,modifiedend |
|||
ENDIF |
|||
ENDIF |
|||
ENDLOOP |
|||
ENDACCESS q |
|||
ERROR/STOP CLOSE (file) |
|||
firstitem=EXCHANGE (firstitem,":{2-00} ::") |
|||
firstitem=INDENT_TAGS (firstitem,-," ") |
|||
names=SPLIT(names) |
|||
TRACE *firstitem,names |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre style='height:30ex;overflow:scroll'> |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
TRACE * 63 -*TUSTEP.EDT |
|||
firstitem = * |
|||
1 = <item upc="123456789" stock="12"> |
|||
2 = <name>Invisibility Cream</name> |
|||
3 = <price>14.50</price> |
|||
4 = <description>Makes you invisible</description> |
|||
5 = </item> |
|||
names = * |
|||
1 = Invisibility Cream |
|||
2 = Levitation Salve |
|||
3 = Blork and Freen Instameal |
|||
4 = Grob winglets |
|||
</pre> |
|||
=={{header|VBScript}}== |
|||
<syntaxhighlight lang="vb"> |
|||
Set objXMLDoc = CreateObject("msxml2.domdocument") |
|||
objXMLDoc.load("In.xml") |
|||
Set item_nodes = objXMLDoc.selectNodes("//item") |
|||
i = 1 |
|||
For Each item In item_nodes |
|||
If i = 1 Then |
|||
WScript.StdOut.Write item.xml |
|||
WScript.StdOut.WriteBlankLines(2) |
|||
Exit For |
|||
End If |
|||
Next |
|||
Set price_nodes = objXMLDoc.selectNodes("//price") |
|||
list_price = "" |
|||
For Each price In price_nodes |
|||
list_price = list_price & price.text & ", " |
|||
Next |
|||
WScript.StdOut.Write list_price |
|||
WScript.StdOut.WriteBlankLines(2) |
|||
Set name_nodes = objXMLDoc.selectNodes("//name") |
|||
list_name = "" |
|||
For Each name In name_nodes |
|||
list_name = list_name & name.text & ", " |
|||
Next |
|||
WScript.StdOut.Write list_name |
|||
WScript.StdOut.WriteBlankLines(2) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
14.50, 23.99, 4.95, 3.56, |
|||
Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets, |
|||
</pre> |
|||
=={{header|Visual Basic .NET}}== |
=={{header|Visual Basic .NET}}== |
||
<syntaxhighlight lang="vbnet">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</syntaxhighlight> |
|||
=={{header|Wren}}== |
|||
{{libheader|Wren-pattern}} |
|||
Wren does not have built-in support for XML/XPath and, to my knowledge, there is no third party module which adds such support either. We therefore have to fall back on string pattern matching to perform the required queries. |
|||
<syntaxhighlight lang="wren">import "./pattern" for Pattern |
|||
var doc = """ |
|||
=={{header|XQuery}}== |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<lang xquery> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
""" |
|||
var p1 = Pattern.new("<item ") |
|||
(: |
|||
var match1 = p1.find(doc) |
|||
var p2 = Pattern.new("<//item>") |
|||
var match2 = p2.find(doc) |
|||
System.print("The first 'item' element is:") |
|||
System.print(" " + doc[match1.index..match2.index + 6]) |
|||
var p3 = Pattern.new("<price>[+1^<]<//price>") |
|||
var matches = p3.findAll(doc) |
|||
System.print("\nThe 'prices' are:") |
|||
for (m in matches) System.print(m.captures[0].text) |
|||
var p4 = Pattern.new("<name>[+1^<]<//name>") |
|||
var matches2 = p4.findAll(doc) |
|||
var names = matches2.map { |m| m.captures[0].text }.toList |
|||
System.print("\nThe 'names' are:") |
|||
System.print(names.join("\n"))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
The first 'item' element is: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
The 'prices' are: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
The 'names' are: |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
<br> |
|||
{{libheader|Wren-xsequence}} |
|||
Since the first version was written, the above XML parser has appeared. Consequently, the solution can now be rewritten as follows, the output being the same as before. |
|||
Note that this library doesn't support XPath as such though for this particular task simple 'for' statements suffice. |
|||
<syntaxhighlight lang="wren">import "./xsequence" for XDocument |
|||
var xml = """ |
|||
<inventory title="OmniCorp Store #45x10^3"> |
|||
<section name="health"> |
|||
<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> |
|||
</section> |
|||
<section name="food"> |
|||
<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> |
|||
</section> |
|||
</inventory> |
|||
""" |
|||
var doc = XDocument.parse(xml) |
|||
System.print("The first 'item' element is:") |
|||
System.print(doc.root.element("section").element("item")) |
|||
var prices = [] |
|||
var names = [] |
|||
for (el in doc.root.elements) { |
|||
for (el2 in el.elements) { |
|||
prices.add(el2.element("price").value) |
|||
names.add(el2.element("name").value) |
|||
} |
|||
} |
|||
System.print("\nThe 'prices' are:\n%(prices.join("\n"))") |
|||
System.print("\nThe 'names' are:\n%(names.join("\n"))")</syntaxhighlight> |
|||
=={{header|XPL0}}== |
|||
To run: xml <xml.xml |
|||
<syntaxhighlight lang "XPL0">include xpllib; \for StrFind |
|||
char XML(1000000), P, P1, P2, Addr; |
|||
int I, Ch; |
|||
[I:= 0; |
|||
loop [Ch:= ChIn(1); |
|||
XML(I):= Ch; |
|||
if Ch = $1A \EOF\ then quit; |
|||
I:= I+1; |
|||
]; |
|||
XML(I):= 0; |
|||
P1:= StrFind(XML, "<item "); |
|||
P2:= StrFind(XML, "</item>"); |
|||
Text(0, "The first 'item' element is:^m^j"); |
|||
for P:= P1 to P2+6 do ChOut(0, P(0)); |
|||
CrLf(0); |
|||
Text(0, "^m^jThe 'prices' are:^m^j"); |
|||
Addr:= XML; |
|||
loop [P1:= StrFind(Addr, "<price>"); |
|||
if P1 = 0 then quit; |
|||
P2:= StrFind(Addr, "</price>"); |
|||
if P2 = 0 then quit; |
|||
for P:= P1+7 to P2-1 do ChOut(0, P(0)); |
|||
CrLf(0); |
|||
Addr:= P2+1; |
|||
]; |
|||
Text(0, "^m^jThe 'names' are:^m^j"); |
|||
Addr:= XML; |
|||
loop [P1:= StrFind(Addr, "<name>"); |
|||
if P1 = 0 then quit; |
|||
P2:= StrFind(Addr, "</name>"); |
|||
if P2 = 0 then quit; |
|||
for P:= P1+6 to P2-1 do ChOut(0, P(0)); |
|||
CrLf(0); |
|||
Addr:= P2+1; |
|||
]; |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
The first 'item' element is: |
|||
<item upc="123456789" stock="12"> |
|||
<name>Invisibility Cream</name> |
|||
<price>14.50</price> |
|||
<description>Makes you invisible</description> |
|||
</item> |
|||
The 'prices' are: |
|||
14.50 |
|||
23.99 |
|||
4.95 |
|||
3.56 |
|||
The 'names' are: |
|||
Invisibility Cream |
|||
Levitation Salve |
|||
Blork and Freen Instameal |
|||
Grob winglets |
|||
</pre> |
|||
=={{header|XProc}}== |
|||
<syntaxhighlight lang="xml"><p:pipeline xmlns:p="http://www.w3.org/ns/xproc" |
|||
name="one-two-three" |
|||
version="1.0"> |
|||
<p:identity> |
|||
<p:input port="source"> |
|||
<p:inline> |
|||
<root> |
|||
<first/> |
|||
<prices/> |
|||
<names/> |
|||
</root> |
|||
</p:inline> |
|||
</p:input> |
|||
</p:identity> |
|||
<p:insert match="/root/first" position="first-child"> |
|||
<p:input port="insertion" select="(//item)[1]"> |
|||
<p:pipe port="source" step="one-two-three"/> |
|||
</p:input> |
|||
</p:insert> |
|||
<p:insert match="/root/prices" position="first-child"> |
|||
<p:input port="insertion" select="//price"> |
|||
<p:pipe port="source" step="one-two-three"/> |
|||
</p:input> |
|||
</p:insert> |
|||
<p:insert match="/root/names" position="first-child"> |
|||
<p:input port="insertion" select="//name"> |
|||
<p:pipe port="source" step="one-two-three"/> |
|||
</p:input> |
|||
</p:insert> |
|||
</p:pipeline></syntaxhighlight> |
|||
=={{header|XQuery}}== |
|||
<syntaxhighlight lang="xquery">(: |
|||
1. Retrieve the first "item" element |
1. Retrieve the first "item" element |
||
Notice the braces around //item. This evaluates first all item elements and then retrieving the first one. |
Notice the braces around //item. This evaluates first all item elements and then retrieving the first one. |
||
Line 569: | Line 4,048: | ||
<prices>{$price}</prices> |
<prices>{$price}</prices> |
||
<names>{$names}</names> |
<names>{$names}</names> |
||
</result> |
</result></syntaxhighlight> |
||
</lang> |
|||
Performing this XQuery on the given input document results in |
Performing this XQuery on the given input document results in |
||
<syntaxhighlight lang="xquery"><?xml version="1.0" encoding="UTF-8"?> |
|||
<lang> |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<result> |
<result> |
||
<firstItem> |
<firstItem> |
||
Line 590: | Line 4,067: | ||
<name>Grob winglets</name> |
<name>Grob winglets</name> |
||
</names> |
</names> |
||
</result> |
</result></syntaxhighlight> |
||
</lang> |
|||
=={{header|XSLT}}== |
=={{header|XSLT}}== |
||
<syntaxhighlight lang="xml"><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
|||
<pre><nowiki> |
|||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
|||
<xsl:output method="text" /> |
<xsl:output method="text" /> |
||
<xsl:template match="/"> |
<xsl:template match="/"> |
||
Line 619: | Line 4,093: | ||
<xsl:copy-of select="//name" /> |
<xsl:copy-of select="//name" /> |
||
</xsl:template> |
</xsl:template> |
||
</xsl:stylesheet> |
</xsl:stylesheet></syntaxhighlight> |
||
</nowiki></pre> |
|||
{{omit from|Batch File|No way of XML parsing or processing.}} |
|||
{{omit from|PARI/GP|No real capacity for string manipulation}} |
Latest revision as of 20:44, 27 March 2024
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:
- //item[1]: Retrieve the first "item" element
- //price/text(): Perform an action on each "price" element (print it out)
- //name: 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>
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program xpathXml64.s */
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ NBMAXELEMENTS, 100
/*******************************************/
/* Structures */
/********************************************/
/* structure xmlNode*/
.struct 0
xmlNode_private: // application data
.struct xmlNode_private + 8
xmlNode_type: // type number, must be second !
.struct xmlNode_type + 8
xmlNode_name: // the name of the node, or the entity
.struct xmlNode_name + 8
xmlNode_children: // parent->childs link
.struct xmlNode_children + 8
xmlNode_last: // last child link
.struct xmlNode_last + 8
xmlNode_parent: // child->parent link
.struct xmlNode_parent + 8
xmlNode_next: // next sibling link
.struct xmlNode_next + 8
xmlNode_prev: // previous sibling link
.struct xmlNode_prev + 8
xmlNode_doc: // the containing document
.struct xmlNode_doc + 8
xmlNode_ns: // pointer to the associated namespace
.struct xmlNode_ns + 8
xmlNode_content: // the content
.struct xmlNode_content + 8
xmlNode_properties: // properties list
.struct xmlNode_properties + 8
xmlNode_nsDef: // namespace definitions on this node
.struct xmlNode_nsDef + 8
xmlNode_psvi: // for type/PSVI informations
.struct xmlNode_psvi + 8
xmlNode_line: // line number
.struct xmlNode_line + 4
xmlNode_extra: // extra data for XPath/XSLT
.struct xmlNode_extra + 4
xmlNode_fin:
/********************************************/
/* structure xmlNodeSet*/
.struct 0
xmlNodeSet_nodeNr: // number of nodes in the set
.struct xmlNodeSet_nodeNr + 4
xmlNodeSet_nodeMax: // size of the array as allocated
.struct xmlNodeSet_nodeMax + 4
xmlNodeSet_nodeTab: // array of nodes in no particular order
.struct xmlNodeSet_nodeTab + 8
xmlNodeSet_fin:
/********************************************/
/* structure xmlXPathObject*/
.struct 0
xmlPathObj_type: //
.struct xmlPathObj_type + 8
xmlPathObj_nodesetval: //
.struct xmlPathObj_nodesetval + 8
xmlPathObj_boolval: //
.struct xmlPathObj_boolval + 8
xmlPathObj_floatval: //
.struct xmlPathObj_floatval + 8
xmlPathObj_stringval: //
.struct xmlPathObj_stringval + 8
xmlPathObj_user: //
.struct xmlPathObj_user + 8
xmlPathObj_index: //
.struct xmlPathObj_index + 8
xmlPathObj_usex2: //
.struct xmlPathObj_usex2 + 8
xmlPathObj_index2: //
.struct xmlPathObj_index2 + 8
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessEndpgm: .asciz "\nNormal end of program.\n"
szMessDisVal: .asciz "\nDisplay set values.\n"
szMessDisArea: .asciz "\nDisplay area values.\n"
szFileName: .asciz "testXml.xml"
szMessError: .asciz "Error detected !!!!. \n"
szLibName: .asciz "name"
szLibPrice: .asciz "//price"
szLibExtName: .asciz "//name"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
tbExtract: .skip 8 * NBMAXELEMENTS // result extract area
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszFileName
bl xmlParseFile // create doc
cbz x0,99f // error ?
mov x19,x0 // doc address
mov x0,x19 // doc
bl xmlDocGetRootElement // get root
bl xmlFirstElementChild // get first section
bl xmlFirstElementChild // get first item
bl xmlFirstElementChild // get first name
bl xmlNodeGetContent // extract content
bl affichageMess // for display
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszMessDisVal
bl affichageMess
mov x0,x19
ldr x1,qAdrszLibPrice // extract prices
bl extractValue
mov x0,x19
ldr x1,qAdrszLibExtName // extract names
bl extractValue
ldr x0,qAdrszMessDisArea
bl affichageMess
mov x4,#0 // display string result area
ldr x5,qAdrtbExtract
1:
ldr x0,[x5,x4,lsl #3]
cbz x0,2f
bl affichageMess
ldr x0,qAdrszCarriageReturn
bl affichageMess
add x4,x4,1
b 1b
2:
mov x0,x19
bl xmlFreeDoc
bl xmlCleanupParser
ldr x0,qAdrszMessEndpgm
bl affichageMess
b 100f
99: // error
ldr x0,qAdrszMessError
bl affichageMess
100: // standard end of the program
mov x0,0 // return code
mov x8,EXIT // request to exit program
svc 0 // perform the system call
qAdrszMessError: .quad szMessError
qAdrszMessEndpgm: .quad szMessEndpgm
qAdrszLibName: .quad szLibName
qAdrszLibPrice: .quad szLibPrice
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrszFileName: .quad szFileName
qAdrszLibExtName: .quad szLibExtName
qAdrtbExtract: .quad tbExtract
qAdrszMessDisVal: .quad szMessDisVal
qAdrszMessDisArea: .quad szMessDisArea
/******************************************************************/
/* extract value of set */
/******************************************************************/
/* x0 contains the doc address
/* x1 contains the address of the libel to extract */
extractValue:
stp x19,lr,[sp,-16]! // save registers
stp x20,x21,[sp,-16]! // save registers
stp x22,x23,[sp,-16]! // save registers
mov x20,x1 // save address libel
mov x19,x0 // save doc
bl xmlXPathNewContext // create context
mov x23,x0 // save context
mov x1,x0
mov x0,x20
bl xmlXPathEvalExpression
mov x21,x0
mov x0,x23
bl xmlXPathFreeContext // free context
cmp x21,#0
beq 100f
ldr x14,[x21,#xmlPathObj_nodesetval] // values set
ldr w23,[x14,#xmlNodeSet_nodeNr] // set size
mov x22,#0 // index
ldr x20,[x14,#xmlNodeSet_nodeTab] // area of nodes
ldr x21,qAdrtbExtract
1: // start loop
ldr x3,[x20,x22,lsl #3] // load node
mov x0,x19
ldr x1,[x3,#xmlNode_children] // load string value
mov x2,#1
bl xmlNodeListGetString
str x0,[x21,x22,lsl #3] // store string pointer in area
bl affichageMess // and display string result
ldr x0,qAdrszCarriageReturn
bl affichageMess
add x22,x22,1
cmp x22,x23
blt 1b
100:
ldp x22,x23,[sp],16 // restaur 2 registers
ldp x20,x21,[sp],16 // restaur 2 registers
ldp x19,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
- Output:
Invisibility Cream Display set values. 14.50 23.99 4.95 3.56 Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets Display area values. Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets Normal end of program.
AppleScript
Using System Events
AppleScript has no-built in support for XPath, but it could be used via a 'do shell script' command. Here's a solution using Apple System Events.
set theXMLdata to "<inventory title=\"OmniCorp Store #45x10^3\">
<section name=\"health\">
<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>
</section>
<section name=\"food\">
<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>
</section>
</inventory>"
on getElementValuesByName(theXML, theNameToFind)
set R to {}
tell application "System Events"
repeat with i in theXML
set {theName, theElements} to {i's name, i's XML elements}
if (count of theElements) > 0 then set R to R & my getElementValuesByName(theElements, theNameToFind)
if theName = theNameToFind then set R to R & i's value
end repeat
end tell
return R
end getElementValuesByName
on getBlock(theXML, theItem, theInstance)
set text item delimiters to ""
repeat with i from 1 to theInstance
set {R, blockStart, blockEnd} to {{}, "<" & theItem & space, "</" & theItem & ">"}
set x to offset of blockStart in theXML
if x = 0 then exit repeat
set y to offset of blockEnd in (characters x thru -1 of theXML as string)
if y = 0 then exit repeat
set R to characters x thru (x + y + (length of blockEnd) - 2) of theXML as string
set theXML to characters (y + (length of blockEnd)) thru -1 of theXML as string
end repeat
return R
end getBlock
tell application "System Events"
set xmlData to make new XML data with properties {name:"xmldata", text:theXMLdata}
return my getBlock(xmlData's text, "item", 1) -- Solution to part 1 of problem.
return my getElementValuesByName(xmlData's contents, "name") -- Solution to part 2 of problem.
return my getElementValuesByName(xmlData's contents, "price") -- Solution to part 3 of problem.
end tell
Output for the three results (respectively):
"<item upc=\"123456789\" stock=\"12\">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>"
{"Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"}
{"14.50", "23.99", "4.95", "3.56"}
ARM Assembly
/* ARM assembly Raspberry PI */
/* program xpathXml.s */
/* Constantes */
.equ STDOUT, 1 @ Linux output console
.equ EXIT, 1 @ Linux syscall
.equ WRITE, 4 @ Linux syscall
.equ NBMAXELEMENTS, 100
/*******************************************/
/* Structures */
/********************************************/
/* structure xmlNode*/
.struct 0
xmlNode_private: @ application data
.struct xmlNode_private + 4
xmlNode_type: @ type number, must be second !
.struct xmlNode_type + 4
xmlNode_name: @ the name of the node, or the entity
.struct xmlNode_name + 4
xmlNode_children: @ parent->childs link
.struct xmlNode_children + 4
xmlNode_last: @ last child link
.struct xmlNode_last + 4
xmlNode_parent: @ child->parent link
.struct xmlNode_parent + 4
xmlNode_next: @ next sibling link
.struct xmlNode_next + 4
xmlNode_prev: @ previous sibling link
.struct xmlNode_prev + 4
xmlNode_doc: @ the containing document
.struct xmlNode_doc + 4
xmlNode_ns: @ pointer to the associated namespace
.struct xmlNode_ns + 4
xmlNode_content: @ the content
.struct xmlNode_content + 4
xmlNode_properties: @ properties list
.struct xmlNode_properties + 4
xmlNode_nsDef: @ namespace definitions on this node
.struct xmlNode_nsDef + 4
xmlNode_psvi: @ for type/PSVI informations
.struct xmlNode_psvi + 4
xmlNode_line: @ line number
.struct xmlNode_line + 4
xmlNode_extra: @ extra data for XPath/XSLT
.struct xmlNode_extra + 4
xmlNode_fin:
/********************************************/
/* structure xmlNodeSet*/
.struct 0
xmlNodeSet_nodeNr: @ number of nodes in the set
.struct xmlNodeSet_nodeNr + 4
xmlNodeSet_nodeMax: @ size of the array as allocated
.struct xmlNodeSet_nodeMax + 4
xmlNodeSet_nodeTab: @ array of nodes in no particular order
.struct xmlNodeSet_nodeTab + 4
xmlNodeSet_fin:
/********************************************/
/* structure xmlXPathObject*/
.struct 0
xmlPathObj_type: @
.struct xmlPathObj_type + 4
xmlPathObj_nodesetval: @
.struct xmlPathObj_nodesetval + 4
xmlPathObj_boolval: @
.struct xmlPathObj_boolval + 4
xmlPathObj_floatval: @
.struct xmlPathObj_floatval + 4
xmlPathObj_stringval: @
.struct xmlPathObj_stringval + 4
xmlPathObj_user: @
.struct xmlPathObj_user + 4
xmlPathObj_index: @
.struct xmlPathObj_index + 4
xmlPathObj_user2: @
.struct xmlPathObj_user2 + 4
xmlPathObj_index2: @
.struct xmlPathObj_index2 + 4
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessEndpgm: .asciz "\nNormal end of program.\n"
szMessDisVal: .asciz "\nDisplay set values.\n"
szMessDisArea: .asciz "\nDisplay area values.\n"
szFileName: .asciz "testXml.xml"
szMessError: .asciz "Error detected !!!!. \n"
szLibName: .asciz "name"
szLibPrice: .asciz "//price"
szLibExtName: .asciz "//name"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
tbExtract: .skip 4 * NBMAXELEMENTS @ result extract area
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszFileName
bl xmlParseFile @ create doc
mov r9,r0 @ doc address
mov r0,r9 @ doc
bl xmlDocGetRootElement @ get root
bl xmlFirstElementChild @ get first section
bl xmlFirstElementChild @ get first item
bl xmlFirstElementChild @ get first name
bl xmlNodeGetContent @ extract content
bl affichageMess @ for display
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszMessDisVal
bl affichageMess
mov r0,r9
ldr r1,iAdrszLibPrice @ extract prices
bl extractValue
mov r0,r9
ldr r1,iAdrszLibExtName @ extact names
bl extractValue
ldr r0,iAdrszMessDisArea
bl affichageMess
mov r4,#0 @ display string result area
ldr r5,iAdrtbExtract
1:
ldr r0,[r5,r4,lsl #2]
cmp r0,#0
beq 2f
bl affichageMess
ldr r0,iAdrszCarriageReturn
bl affichageMess
add r4,#1
b 1b
2:
mov r0,r9
bl xmlFreeDoc
bl xmlCleanupParser
ldr r0,iAdrszMessEndpgm
bl affichageMess
b 100f
99:
@ error
ldr r0,iAdrszMessError
bl affichageMess
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszMessError: .int szMessError
iAdrszMessEndpgm: .int szMessEndpgm
iAdrszLibName: .int szLibName
iAdrszLibPrice: .int szLibPrice
iAdrszCarriageReturn: .int szCarriageReturn
iAdrszFileName: .int szFileName
iAdrszLibExtName: .int szLibExtName
iAdrtbExtract: .int tbExtract
iAdrszMessDisVal: .int szMessDisVal
iAdrszMessDisArea: .int szMessDisArea
/******************************************************************/
/* extract value of set */
/******************************************************************/
/* r0 contains the doc address
/* r1 contains the address of the libel to extract */
extractValue:
push {r1-r10,lr} @ save registres
mov r4,r1 @ save address libel
mov r9,r0 @ save doc
ldr r8,iAdrtbExtract
bl xmlXPathNewContext @ create context
mov r10,r0
mov r1,r0
mov r0,r4
bl xmlXPathEvalExpression
mov r5,r0
mov r0,r10
bl xmlXPathFreeContext @ free context
cmp r5,#0
beq 100f
ldr r4,[r5,#xmlPathObj_nodesetval] @ values set
ldr r6,[r4,#xmlNodeSet_nodeNr] @ set size
mov r7,#0 @ index
ldr r4,[r4,#xmlNodeSet_nodeTab] @ area of nods
1: @ start loop
ldr r3,[r4,r7,lsl #2] @ load node
mov r0,r9
ldr r1,[r3,#xmlNode_children] @ load string value
mov r2,#1
bl xmlNodeListGetString
str r0,[r8,r7,lsl #2] @ store string pointer in area
bl affichageMess @ and display string result
ldr r0,iAdrszCarriageReturn
bl affichageMess
add r7,#1
cmp r7,r6
blt 1b
100:
pop {r1-r10,lr} @ restaur registers */
bx lr @ return
/******************************************************************/
/* display text with size calculation */
/******************************************************************/
/* r0 contains the address of the message */
affichageMess:
push {r0,r1,r2,r7,lr} @ save registres
mov r2,#0 @ counter length
1: @ loop length calculation
ldrb r1,[r0,r2] @ read octet start position + index
cmp r1,#0 @ if 0 its over
addne r2,r2,#1 @ else add 1 in the length
bne 1b @ and loop
@ so here r2 contains the length of the message
mov r1,r0 @ address message in r1
mov r0,#STDOUT @ code to write to the standard output Linux
mov r7, #WRITE @ code call system "write"
svc #0 @ call systeme
pop {r0,r1,r2,r7,lr} @ restaur registers */
bx lr @ return
- Output:
Invisibility Cream Display set values. 14.50 23.99 4.95 3.56 Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets Display area values. Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets Normal end of program.
AutoHotkey
With regular expressions
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
#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")
Bracmat
{Retrieve the first "item" element}
( nestML$(get$("doc.xml",X,ML))
: ?
( inventory
. ?,? (section.?,? ((item.?):?item) ?) ?
)
?
& out$(toML$!item)
)
{Perform an action on each "price" element (print it out)}
( nestML$(get$("doc.xml",X,ML))
: ?
( inventory
. ?
, ?
( section
. ?
, ?
( item
. ?
, ?
( price
. ?
, ?price
& out$!price
& ~
)
?
)
?
)
?
)
?
|
)
{Get an array of all the "name" elements}
( :?anArray
& nestML$(get$("doc.xml",X,ML))
: ?
( inventory
. ?
, ?
( section
. ?
, ?
( item
. ?
, ?
( name
. ?
, ?name
& !anArray !name:?anArray
& ~
)
?
)
?
)
?
)
?
| out$!anArray {Not truly an array, but a list.}
);
C
Takes XML document and XPath expression as inputs and prints results, usage is printed if invoked incorrectly.
#include <libxml/parser.h>
#include <libxml/xpath.h>
xmlDocPtr getdoc (char *docname) {
xmlDocPtr doc;
doc = xmlParseFile(docname);
return doc;
}
xmlXPathObjectPtr getnodeset (xmlDocPtr doc, xmlChar *xpath){
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
context = xmlXPathNewContext(doc);
result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
return result;
}
int main(int argc, char **argv) {
if (argc <= 2) {
printf("Usage: %s <XML Document Name> <XPath expression>\n", argv[0]);
return 0;
}
char *docname;
xmlDocPtr doc;
xmlChar *xpath = (xmlChar*) argv[2];
xmlNodeSetPtr nodeset;
xmlXPathObjectPtr result;
int i;
xmlChar *keyword;
docname = argv[1];
doc = getdoc(docname);
result = getnodeset (doc, xpath);
if (result) {
nodeset = result->nodesetval;
for (i=0; i < nodeset->nodeNr; i++) {
xmlNodePtr titleNode = nodeset->nodeTab[i];
keyword = xmlNodeListGetString(doc, titleNode->xmlChildrenNode, 1);
printf("Value %d: %s\n",i+1, keyword);
xmlFree(keyword);
}
xmlXPathFreeObject (result);
}
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
testXML.xml contains the XML mentioned in the task description. Code must be compiled with the correct flags.
C:\rosettaCode>xPather.exe testXML.xml //price Value 1: 14.50 Value 2: 23.99 Value 3: 4.95 Value 4: 3.56 C:\rosettaCode>xPather.exe testXML.xml //name Value 1: Invisibility Cream Value 2: Levitation Salve Value 3: Blork and Freen Instameal Value 4: Grob winglets
C#
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);
C++
The following code uses each of the three tasks given to demonstrate a different method of handling the resulting node set from an XPath query.
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <utility>
#include <vector>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xmlstring.h>
#include <libxml/xmlversion.h>
#include <libxml/xpath.h>
#ifndef LIBXML_XPATH_ENABLED
# error libxml was not configured with XPath support
#endif
// Because libxml2 is a C library, we need a couple things to make it work
// well with modern C++:
// 1) a ScopeGuard-like type to handle cleanup functions; and
// 2) an exception type that transforms the library's errors.
// ScopeGuard-like type to handle C library cleanup functions.
template <typename F>
class [[nodiscard]] scope_exit
{
public:
// C++20: Constructor can (and should) be [[nodiscard]].
/*[[nodiscard]]*/ constexpr explicit scope_exit(F&& f) :
f_{std::move(f)}
{}
~scope_exit()
{
f_();
}
// Non-copyable, non-movable.
scope_exit(scope_exit const&) = delete;
scope_exit(scope_exit&&) = delete;
auto operator=(scope_exit const&) -> scope_exit& = delete;
auto operator=(scope_exit&&) -> scope_exit& = delete;
private:
F f_;
};
// Exception that gets last libxml2 error.
class libxml_error : public std::runtime_error
{
public:
libxml_error() : libxml_error(std::string{}) {}
explicit libxml_error(std::string message) :
std::runtime_error{make_message_(std::move(message))}
{}
private:
static auto make_message_(std::string message) -> std::string
{
if (auto const last_error = ::xmlGetLastError(); last_error)
{
if (not message.empty())
message += ": ";
message += last_error->message;
}
return message;
}
};
auto main() -> int
{
try
{
// Initialize libxml.
::xmlInitParser();
LIBXML_TEST_VERSION
auto const libxml_cleanup = scope_exit{[] { ::xmlCleanupParser(); }};
// Load and parse XML document.
auto const doc = ::xmlParseFile("test.xml");
if (not doc)
throw libxml_error{"failed to load document"};
auto const doc_cleanup = scope_exit{[doc] { ::xmlFreeDoc(doc); }};
// Create XPath context for document.
auto const xpath_context = ::xmlXPathNewContext(doc);
if (not xpath_context)
throw libxml_error{"failed to create XPath context"};
auto const xpath_context_cleanup = scope_exit{[xpath_context]
{ ::xmlXPathFreeContext(xpath_context); }};
// Task 1 ============================================================
{
std::cout << "Task 1:\n";
auto const xpath =
reinterpret_cast<::xmlChar const*>(u8"//item[1]");
// Create XPath object (same for every task).
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context);
if (not xpath_obj)
throw libxml_error{"failed to evaluate XPath"};
auto const xpath_obj_cleanup = scope_exit{[xpath_obj]
{ ::xmlXPathFreeObject(xpath_obj); }};
// 'result' a xmlNode* to the desired node, or nullptr if it
// doesn't exist. If not nullptr, the node is owned by 'doc'.
auto const result = xmlXPathNodeSetItem(xpath_obj->nodesetval, 0);
if (result)
std::cout << '\t' << "node found" << '\n';
else
std::cout << '\t' << "node not found" << '\n';
}
// Task 2 ============================================================
{
std::cout << "Task 2:\n";
auto const xpath =
reinterpret_cast<::xmlChar const*>(u8"//price/text()");
// Create XPath object (same for every task).
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context);
if (not xpath_obj)
throw libxml_error{"failed to evaluate XPath"};
auto const xpath_obj_cleanup = scope_exit{[xpath_obj]
{ ::xmlXPathFreeObject(xpath_obj); }};
// Printing the results.
auto const count =
xmlXPathNodeSetGetLength(xpath_obj->nodesetval);
for (auto i = decltype(count){0}; i < count; ++i)
{
auto const node =
xmlXPathNodeSetItem(xpath_obj->nodesetval, i);
assert(node);
auto const content = XML_GET_CONTENT(node);
assert(content);
// Note that reinterpret_cast here is a Bad Idea, because
// 'content' is UTF-8 encoded, which may or may not be the
// encoding cout expects. A *PROPER* solution would translate
// content to the correct encoding (or at least verify that
// UTF-8 *is* the correct encoding).
//
// But this "works" well enough for illustration.
std::cout << "\n\t" << reinterpret_cast<char const*>(content);
}
std::cout << '\n';
}
// Task 3 ============================================================
{
std::cout << "Task 3:\n";
auto const xpath =
reinterpret_cast<::xmlChar const*>(u8"//name");
// Create XPath object (same for every task).
auto xpath_obj = ::xmlXPathEvalExpression(xpath, xpath_context);
if (not xpath_obj)
throw libxml_error{"failed to evaluate XPath"};
auto const xpath_obj_cleanup = scope_exit{[xpath_obj]
{ ::xmlXPathFreeObject(xpath_obj); }};
// 'results' is a vector of pointers to the result nodes. The
// nodes pointed to are owned by 'doc'.
auto const results = [ns=xpath_obj->nodesetval]()
{
auto v = std::vector<::xmlNode*>{};
if (ns && ns->nodeTab)
v.assign(ns->nodeTab, ns->nodeTab + ns->nodeNr);
return v;
}();
std::cout << '\t' << "set of " << results.size()
<< " node(s) found" << '\n';
}
}
catch (std::exception const& x)
{
std::cerr << "ERROR: " << x.what() << '\n';
return EXIT_FAILURE;
}
}
Caché ObjectScript
Class XML.Inventory [ Abstract ]
{
XData XMLData
{
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
}
ClassMethod QueryXMLDoc(Output names As %List) As %Status
{
// get xml stream from the 'XData' block contained in this class
Set xdata=##class(%Dictionary.CompiledXData).%OpenId($this_"||XMLData",, .sc)
If $$$ISERR(sc) Quit sc
Set sc=##class(%XML.XPATH.Document).CreateFromStream(xdata.Data, .xdoc)
If $$$ISERR(sc) Quit sc
// retrieve the first 'item' element
Set sc=xdoc.EvaluateExpression("//section[1]", "item[1]", .res)
// perform an action on each 'price' element (print it out)
Set sc=xdoc.EvaluateExpression("//price", "text()", .res)
If $$$ISERR(sc) Quit sc
For i=1:1:res.Count() {
If i>1 Write ", "
Write res.GetAt(i).Value
}
// get an array of all the 'name' elements
Set sc=xdoc.EvaluateExpression("//item", "name", .res)
If $$$ISERR(sc) Quit sc
Set key=""
Do {
Set dom=res.GetNext(.key)
If '$IsObject(dom) Quit
While dom.Read() {
If dom.HasValue Set $List(names, key)=dom.Value
}
} While key'=""
// finished
Quit $$$OK
}
}
- Examples:
USER>Do ##class(XML.Inventory).QueryXMLDoc(.list) 14.50, 23.99, 4.95, 3.56 USER>Write $ListToString(list, ", ") Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets
CoffeeScript
doc = new DOMParser().parseFromString '
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
', 'text/xml'
# "doc" is the XML as a Document object. Click expand to see parsing code ⇒
# Retrieve the first "item" element
doc.evaluate('//item', doc, {}, 7, {}).snapshotItem 0
# Perform an action on each "price" element (print it out)
prices = doc.evaluate "//price", doc, {}, 7, {}
for i in [0...prices.snapshotLength] by 1
console.log prices.snapshotItem(i).textContent
# Get an array of all the "name" elements
names = doc.evaluate "//name", doc, {}, 7, {}
names = for i in [0...names.snapshotLength] by 1
names.snapshotItem i
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#">
Common Lisp
(dolist (system '(:xpath :cxml-stp :cxml))
(asdf:oos 'asdf:load-op system))
(defparameter *doc* (cxml:parse-file "xml" (stp:make-builder)))
(xpath:first-node (xpath:evaluate "/inventory/section[1]/item[1]" *doc*))
(xpath:do-node-set (node (xpath:evaluate "/inventory/section/item/price/text()" *doc*))
(format t "~A~%" (stp:data node)))
(defun node-array (node-set)
(coerce (xpath:all-nodes node-set) 'vector))
(node-array
(xpath:evaluate "/inventory/section/item/name" *doc*))
D
It is important to note that the KXML library currently only supports XPath minimally.
import kxml.xml;
char[]xmlinput =
"<inventory title=\"OmniCorp Store #45x10^3\">
<section name=\"health\">
<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>
</section>
<section name=\"food\">
<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>
</section>
</inventory>
";
void main() {
auto root = readDocument(xmlinput);
auto firstitem = root.parseXPath("inventory/section/item")[0];
foreach(price;root.parseXPath("inventory/section/item/price")) {
std.stdio.writefln("%s",price.getCData);
}
auto namearray = root.parseXPath("inventory/section/item/name");
}
Delphi
program XMLXPath;
{$APPTYPE CONSOLE}
uses ActiveX, MSXML;
const
XML =
'<inventory title="OmniCorp Store #45x10^3">' +
' <section name="health">' +
' <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>' +
' </section>' +
' <section name="food">' +
' <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>' +
' </section>' +
'</inventory>';
var
i: Integer;
s: string;
lXMLDoc: IXMLDOMDocument2;
lNodeList: IXMLDOMNodeList;
lNode: IXMLDOMNode;
lItemNames: array of string;
begin
CoInitialize(nil);
lXMLDoc := CoDOMDocument.Create;
lXMLDoc.setProperty('SelectionLanguage', 'XPath');
lXMLDoc.loadXML(XML);
Writeln('First item node:');
lNode := lXMLDoc.selectNodes('//item')[0];
Writeln(lNode.xml);
Writeln('');
lNodeList := lXMLDoc.selectNodes('//price');
for i := 0 to lNodeList.length - 1 do
Writeln('Price = ' + lNodeList[i].text);
Writeln('');
lNodeList := lXMLDoc.selectNodes('//item/name');
SetLength(lItemNames, lNodeList.length);
for i := 0 to lNodeList.length - 1 do
lItemNames[i] := lNodeList[i].text;
for s in lItemNames do
Writeln('Item name = ' + s);
end.
Output:
First item node:
<item upc="123456789" stock="12">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>
Price = 14.50
Price = 23.99
Price = 4.95
Price = 3.56
Item name = Invisibility Cream
Item name = Levitation Salve
Item name = Blork and Freen Instameal
Item name = Grob winglets
E
(currently a very early work in progress/draft library; design comments welcome)
? def xml__quasiParser := <import:org.switchb.e.xml.makeXMLQuasiParser>()
> def xpath__quasiParser := xml__quasiParser.xPathQuasiParser()
> null
? def doc := xml`<inventory title="OmniCorp Store #45x10^3">
> <section name="health">
> <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>n>
> </item>
> </section>
> <section name="food">
> <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>
> </section>
> </inventory>`
# value: xml`...`
? doc[xpath`inventory/section/item`][0]
# value: xml`<item stock="12" upc="123456789">
# <name>Invisibility Cream</name>
# <price>14.50</price>
# <description>Makes you invisible</description>
# </item>`
? for price in doc[xpath`inventory/section/item/price/text()`] { println(price :String) }
14.50
23.99
4.95
3.56
? doc[xpath`inventory/section/item/name`]
# value: [xml`<name>Invisibility Cream</name>`,
# xml`<name>Levitation Salve</name>`,
# xml`<name>Blork and Freen Instameal</name>`,
# xml`<name>Grob winglets</name>`]
Erlang
-module(xml_xpath).
-include_lib("xmerl/include/xmerl.hrl").
-export([main/0]).
main() ->
XMLDocument =
"<inventory title=\"OmniCorp Store #45x10^3\">
<section name=\"health\">
<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>
</section>
<section name=\"food\">
<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>
</section>
</inventory>",
{Document,_} = xmerl_scan:string(XMLDocument),
io:format("First item:\n~s\n",
[lists:flatten(
xmerl:export_simple(
[hd(xmerl_xpath:string("//item[1]", Document))],
xmerl_xml, [{prolog, ""}]))]),
io:format("Prices:\n"),
[ io:format("~s\n",[Content#xmlText.value])
|| #xmlElement{content = [Content|_]} <- xmerl_xpath:string("//price", Document)],
io:format("Names:\n"),
[ Content#xmlText.value
|| #xmlElement{content = [Content|_]} <- xmerl_xpath:string("//name", Document)].
Output:
First item: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> Prices: 14.50 23.99 4.95 3.56 Names: ["Invisibility Cream","Levitation Salve", "Blork and Freen Instameal","Grob winglets"]
FreeBASIC
Dim As String XML, item, price, nombre
Dim As Integer P1, P2
'' Read the XML file
Open "test3.xml" For Input As #1
XML = Input(Lof(1), #1)
Close #1
'' Find the first 'item' element
P1 = Instr(XML, "<item ")
P2 = Instr(XML, "</item>")
item = Mid(XML, P1, P2-P1+7)
Print "The first 'item' element is:"
Print item
'' Find all 'price' elements
Print "The 'prices' are:"
P1 = 1
Do
P1 = Instr(P1, XML, "<price>")
If P1 = 0 Then Exit Do
P2 = Instr(P1, XML, "</price>")
price = Mid(XML, P1+7, P2-P1-7)
Print price
P1 = P2 + 1
Loop
'' Find all 'nombre' elements
Print !"\nThe 'names' are:"
P1 = 1
Do
P1 = Instr(P1, XML, "<name>")
If P1 = 0 Then Exit Do
P2 = Instr(P1, XML, "</name>")
nombre = Mid(XML, P1+6, P2-P1-6)
Print nombre
P1 = P2 + 1
Loop
Sleep
F#
open System.IO
open System.Xml.XPath
let xml = new StringReader("""
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
""")
let nav = XPathDocument(xml).CreateNavigator()
// first "item"; throws if none exists
let item = nav.SelectSingleNode(@"//item[1]")
// apply a operation (print text value) to all price elements
for price in nav.Select(@"//price") do
printfn "%s" (price.ToString())
// array of all name elements
let names = seq { for name in nav.Select(@"//name") do yield name } |> Seq.toArray
Factor
! Get first item element
"""<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>""" string>xml "item" deep-tag-named
! Print out prices
"""<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>""" string>xml "price" deep-tags-named [ children>> first ] map
! Array of all name elements
"""<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>""" string>xml "name" deep-tags-named
Gastona
The example uses the command XMELON which parses a XML file of any schema and stores its contents into db tables. This parser is described in the article XMeLon-Schema
#javaj#
<frames> oSal, XML Path sample, 300, 400
#data#
<xml>
//<inventory title="OmniCorp Store #45x10^3">
// <section name="health">
// <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>
// </section>
// <section name="food">
// <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>
// </section>
//</inventory>
<DEEP_SQL_XML>
DEEP DB, SELECT, xmelon_data
,, path pathStr
,, tag tagStr
,, patCnt
,, dataPlace
,, value
#listix#
<main>
//parsing xml data ...
GEN, :mem datos, xml
XMELON, FILE2DB, :mem datos
//
//first item ...
//
//
LOOP, SQL,, //SELECT patCnt AS patITEM1 FROM (@<DEEP_SQL_XML>) WHERE path_pathStr == '/inventory/section/item' LIMIT 1
,HEAD, //<item
,, LOOP, SQL,, //SELECT * FROM (@<DEEP_SQL_XML>) WHERE patCnt == @<patITEM1> AND dataPlace == 'A'
,, , LINK, ""
,, ,, // @<tag_tagStr>="@<value>"
,, //>
,, //
,, LOOP, SQL,, //SELECT * FROM (@<DEEP_SQL_XML>) WHERE patCnt == @<patITEM1> AND dataPlace != 'A'
,, ,, // <@<tag_tagStr>>@<value></@<tag_tagStr>>
,TAIL, //
,TAIL, //</item>
//
//
//report prices ...
//
LOOP, SQL,, //SELECT value FROM (@<DEEP_SQL_XML>) WHERE tag_tagStr == 'price'
, LINK, ", "
,, @<value>
//
//put names into a variable
//
VAR=, tabnames, "name"
LOOP, SQL,, //SELECT value FROM (@<DEEP_SQL_XML>) WHERE tag_tagStr == 'name'
, LINK, ""
,, VAR+, tabnames, @<value>
DUMP, data,, tabnames
- Output:
parsing xml data ... first item ... <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> report prices ... 14.50, 23.99, 4.95, 3.56 names into a variable #data# <tabnames> //name //health //Invisibility Cream //Levitation Salve //food //Blork and Freen Instameal //Grob winglets
Go
Using the standard encoding/xml
package:
package main
import (
"encoding/xml"
"fmt"
"log"
"os"
)
type Inventory struct {
XMLName xml.Name `xml:"inventory"`
Title string `xml:"title,attr"`
Sections []struct {
XMLName xml.Name `xml:"section"`
Name string `xml:"name,attr"`
Items []struct {
XMLName xml.Name `xml:"item"`
Name string `xml:"name"`
UPC string `xml:"upc,attr"`
Stock int `xml:"stock,attr"`
Price float64 `xml:"price"`
Description string `xml:"description"`
} `xml:"item"`
} `xml:"section"`
}
// To simplify main's error handling
func printXML(s string, v interface{}) {
fmt.Println(s)
b, err := xml.MarshalIndent(v, "", "\t")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
fmt.Println()
}
func main() {
fmt.Println("Reading XML from standard input...")
var inv Inventory
dec := xml.NewDecoder(os.Stdin)
if err := dec.Decode(&inv); err != nil {
log.Fatal(err)
}
// At this point, inv is Go struct with all the fields filled
// in from the XML data. Well-formed XML input that doesn't
// match the specification of the fields in the Go struct are
// discarded without error.
// We can reformat the parts we parsed:
//printXML("Got:", inv)
// 1. Retrieve first item:
item := inv.Sections[0].Items[0]
fmt.Println("item variable:", item)
printXML("As XML:", item)
// 2. Action on each price:
fmt.Println("Prices:")
var totalValue float64
for _, s := range inv.Sections {
for _, i := range s.Items {
fmt.Println(i.Price)
totalValue += i.Price * float64(i.Stock)
}
}
fmt.Println("Total inventory value:", totalValue)
fmt.Println()
// 3. Slice of all the names:
var names []string
for _, s := range inv.Sections {
for _, i := range s.Items {
names = append(names, i.Name)
}
}
fmt.Printf("names: %q\n", names)
}
- Output:
Reading XML from standard input... item variable: {{ item} Invisibility Cream 123456789 12 14.5 Makes you invisible} As XML: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.5</price> <description>Makes you invisible</description> </item> Prices: 14.5 23.99 4.95 3.56 Total inventory value: 3994.81 names: ["Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets"]
package main
import (
"fmt"
"os"
"launchpad.net/xmlpath"
)
func main() {
f, err := os.Open("test3.xml")
if err != nil {
fmt.Println(err)
return
}
n, err := xmlpath.Parse(f)
f.Close()
if err != nil {
fmt.Println(err)
return
}
q1 := xmlpath.MustCompile("//item")
if _, ok := q1.String(n); !ok {
fmt.Println("no item")
}
q2 := xmlpath.MustCompile("//price")
for it := q2.Iter(n); it.Next(); {
fmt.Println(it.Node())
}
q3 := xmlpath.MustCompile("//name")
names := []*xmlpath.Node{}
for it := q3.Iter(n); it.Next(); {
names = append(names, it.Node())
}
if len(names) == 0 {
fmt.Println("no names")
}
}
- Output:
14.50 23.99 4.95 3.56
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
Haskell
import Data.List
import Control.Arrow
import Control.Monad
takeWhileIncl :: (a -> Bool) -> [a] -> [a]
takeWhileIncl _ [] = []
takeWhileIncl p (x:xs)
| p x = x : takeWhileIncl p xs
| otherwise = [x]
getmultiLineItem n = takeWhileIncl(not.isInfixOf ("</" ++ n)). dropWhile(not.isInfixOf ('<': n))
getsingleLineItems n = map (takeWhile(/='<'). drop 1. dropWhile(/='>')). filter (isInfixOf ('<': n))
main = do
xml <- readFile "./Rosetta/xmlpath.xml"
let xmlText = lines xml
putStrLn "\n== First item ==\n"
mapM_ putStrLn $ head $ unfoldr (Just. liftM2 (id &&&) (\\) (getmultiLineItem "item")) xmlText
putStrLn "\n== Prices ==\n"
mapM_ putStrLn $ getsingleLineItems "price" xmlText
putStrLn "\n== Names ==\n"
print $ getsingleLineItems "name" xmlText
Using the Haskell XML Toolkit (HXT):
{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Arrow
{- For HXT version >= 9.0, use instead:
import Text.XML.HXT.Core
-}
deepElem name = deep (isElem >>> hasName name)
process = proc doc -> do
item <- single (deepElem "item") -< doc
_ <- listA (arrIO print <<< deepElem "price") -< doc
names <- listA (deepElem "name") -< doc
returnA -< (item, names)
main = do
[(item, names)] <- runX (readDocument [] "xmlpath.xml" >>> process)
print item
print names
HicEst
CHARACTER xml*1000, output*1000
READ(ClipBoard) xml
EDIT(Text=xml, Right='<item', Right=5, GetPosition=a, Right='</item>', Left, GetPosition=z)
WRITE(Text=output) xml( a : z), $CRLF
i = 1
1 EDIT(Text=xml, SetPosition=i, SePaRators='<>', Right='<price>', Word=1, Parse=price, GetPosition=i, ERror=99)
IF(i > 0) THEN
WRITE(Text=output, APPend) 'Price element = ', price, $CRLF
GOTO 1 ! HicEst does not have a "WHILE"
ENDIF
EDIT(Text=xml, SPR='<>', R='<name>', W=1, WordEnd=$CR, APpendTo=output, DO=999)
WRITE(ClipBoard) TRIM(output)
upc="123456789" stock="12">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
Price element = 14.50
Price element = 23.99
Price element = 4.95
Price element = 3.56
Invisibility Cream
Levitation Salve
Blork and Freen Instameal
Grob winglets
Java
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class XMLParser {
final static String xmlStr =
"<inventory title=\"OmniCorp Store #45x10^3\">"
+ " <section name=\"health\">"
+ " <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>"
+ " </section>"
+ " <section name=\"food\">"
+ " <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 priwater</description>"
+ " </item>"
+ " </section>"
+ "</inventory>";
public static void main(String[] args) {
try {
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new InputSource(new StringReader(xmlStr)));
XPath xpath = XPathFactory.newInstance().newXPath();
// 1
System.out.println(((Node) xpath.evaluate(
"/inventory/section/item[1]", doc, XPathConstants.NODE))
.getAttributes().getNamedItem("upc"));
// 2, 3
NodeList nodes = (NodeList) xpath.evaluate(
"/inventory/section/item/price", doc,
XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++)
System.out.println(nodes.item(i).getTextContent());
} catch (Exception e) {
System.out.println("Error ocurred while parsing XML.");
}
}
}
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 );
Although some browsers support XPath, working with XML is much easier with E4X.
//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 );
Julia
Uses the LibExpat module for XML pathing. The exercise description is very vague about output format, so this is varied in the solution below. The first test prints the raw XML node, and the second and third are further processed.
using LibExpat
xdoc = raw"""<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
"""
debracket(s) = replace(s, r".+\>(.+)\<.+" => s"\1")
etree = xp_parse(xdoc)
firstshow = LibExpat.find(etree, "//item")[1]
println("The first item's node XML entry is:\n", firstshow, "\n\n")
prices = LibExpat.find(etree, "//price")
println("Prices:")
for p in prices
println("\t", debracket(string(p)))
end
println("\n")
namearray = LibExpat.find(etree, "//name")
println("Array of names of items:\n\t", map(s -> debracket(string(s)), namearray))
- Output:
The first item's node XML entry is: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item>
Prices: 14.50 23.99 4.95 3.56
Array of names of items: ["Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"]
Kotlin
// version 1.1.3
import javax.xml.parsers.DocumentBuilderFactory
import org.xml.sax.InputSource
import java.io.StringReader
import javax.xml.xpath.XPathFactory
import javax.xml.xpath.XPathConstants
import org.w3c.dom.Node
import org.w3c.dom.NodeList
val xml =
"""
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
"""
fun main(args: Array<String>) {
val dbFactory = DocumentBuilderFactory.newInstance()
val dBuilder = dbFactory.newDocumentBuilder()
val xmlInput = InputSource(StringReader(xml))
val doc = dBuilder.parse(xmlInput)
val xpFactory = XPathFactory.newInstance()
val xPath = xpFactory.newXPath()
val qNode = xPath.evaluate("/inventory/section/item[1]", doc, XPathConstants.NODE) as Node
val upc = qNode.attributes.getNamedItem("upc")
val stock = qNode.attributes.getNamedItem("stock")
println("For the first item : upc = ${upc.textContent} and stock = ${stock.textContent}")
val qNodes = xPath.evaluate("/inventory/section/item/price", doc, XPathConstants.NODESET) as NodeList
print("\nThe prices of each item are : ")
for (i in 0 until qNodes.length) print("${qNodes.item(i).textContent} ")
println()
val qNodes2 = xPath.evaluate("/inventory/section/item/name", doc, XPathConstants.NODESET) as NodeList
val names = Array<String>(qNodes2.length) { qNodes2.item(it).textContent }
println("\nThe names of each item are as follows :")
println(" ${names.joinToString("\n ")}")
}
- Output:
For the first item : upc = 123456789 and stock = 12 The prices of each item are : 14.50 23.99 4.95 3.56 The names of each item are as follows : Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
Ksh
#!/bin/ksh
# Perform XPath queries on a XML Document
# # Variables:
#
typeset -T Xml_t=(
typeset -h 'UPC' upc
typeset -i -h 'num in stock' stock=0
typeset -h 'name' name
typeset -F2 -h 'price' price
typeset -h 'description' description
function init_item {
typeset key ; key="$1"
typeset val ; val="${2%\<\/${key}*}"
case ${key} in
upc) _.upc="${val//@(\D)/}"
;;
stock) _.stock="${val//@(\D)/}"
;;
name) _.name="${val%\<\/${key}*}"
;;
price) _.price="${val}"
;;
description) _.description=$(echo ${val})
;;
esac
}
function prt_item {
print "upc= ${_.upc}"
print "stock= ${_.stock}"
print "name= ${_.name}"
print "price= ${_.price}"
print "description= ${_.description}"
}
)
# # Functions:
#
######
# main #
######
integer i=0
typeset -a Item_t
buff=$(< xmldoc) # read xmldoc
item=${buff%%'</item>'*} ; buff=${.sh.match}
while [[ -n ${item} ]]; do
Xml_t Item_t[i]
item=${item#*'<item'} ; item=$(echo ${item})
for word in ${item}; do
if [[ ${word} == *=* ]]; then
Item_t[i].init_item ${word%\=*} ${word#*\=}
else
if [[ ${word} == \<* ]]; then # Beginning
key=${word%%\>*} ; key=${key#*\<}
val=${word#*\>}
fi
[[ ${word} != \<* && ${word} != *\> ]] && val+=" ${word} "
if [[ ${word} == *\> ]]; then # End
val+=" ${word%\<${key}\>*}"
Item_t[i].init_item "${key}" "${val}"
fi
fi
done
(( i++ ))
item=${buff#*'</item>'} ; item=${item%%'</item>'*} ; buff=${.sh.match}
done
print "First Item element:"
Item_t[0].prt_item
typeset -a names
printf "\nList of prices:\n"
for ((i=0; i<${#Item_t[*]}-1; i++)); do
print ${Item_t[i].price}
names[i]=${Item_t[i].name}
done
printf "\nArray of names:\n"
for (( i=0; i<${#names[*]}; i++)); do
print "names[$i] = ${names[i]}"
done
- Output:
First Item element: upc= 123456789 stock= 12 name= Invisibility Cream price= 14.50 description= Makes you invisible
List of prices: 14.50 23.99 4.95 3.56
Array of names: names[0] = Invisibility Cream names[1] = Levitation Salve names[2] = Blork and Freen Instameal
names[3] = Grob winglets
Lasso
Lasso has built in support for both XML handling and Xpaths
// makes extracting attribute values easier
define xml_attrmap(in::xml_namedNodeMap_attr) => {
local(out = map)
with attr in #in
do #out->insert(#attr->name = #attr->value)
return #out
}
local(
text = '<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
',
xml = xml(#text)
)
local(
items = #xml -> extract('//item'),
firstitem = #items -> first,
itemattr = xml_attrmap(#firstitem -> attributes),
newprices = array
)
'<strong>First item:</strong><br />
UPC: '
#itemattr -> find('upc')
' (stock: '
#itemattr -> find('stock')
')<br />'
#firstitem -> extractone('name') -> nodevalue
' ['
#firstitem -> extractone('price') -> nodevalue
'] ('
#firstitem -> extractone('description') -> nodevalue
')<br /><br />'
with item in #items
let name = #item -> extractone('name') -> nodevalue
let price = #item -> extractone('price') -> nodevalue
do {
#newprices -> insert(#name + ': ' + (decimal(#price) * 1.10) -> asstring(-precision = 2) + ' (' + #price + ')')
}
'<strong>Adjusted prices:</strong><br />'
#newprices -> join('<br />')
'<br /><br />'
'<strong>Array with all names:</strong><br />'
#xml -> extract('//name') -> asstaticarray
Output:
First item: UPC: 123456789 (stock: 12) Invisibility Cream [14.50] (Makes you invisible) Adjusted prices: Invisibility Cream: 15.95 (14.50) Levitation Salve: 26.39 (23.99) Blork and Freen Instameal: 5.45 (4.95) Grob winglets: 3.92 (3.56) Array with all names: staticarray(Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets)
LiveCode
Copy the xml in this task into a text field called "FieldXML"
put revXMLCreateTree(fld "FieldXML",true,true,false) into xmltree
// task 1
put revXMLEvaluateXPath(xmltree,"//item[1]") into nodepath
put revXMLText(xmltree,nodepath,true)
// task 2
put revXMLDataFromXPathQuery(xmltree,"//item/price",,comma)
// task 3
put revXMLDataFromXPathQuery(xmltree,"//name") into namenodes
filter namenodes without empty
split namenodes using cr
put namenodes is an array
Lua
Requires LuaExpat
require 'lxp'
data = [[<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>]]
local first = true
local names, prices = {}, {}
p = lxp.new({StartElement = function (parser, name)
local a, b, c = parser:pos() --line, offset, pos
if name == 'item' and first then
print(data:match('.-</item>', c - b + 1))
first = false
end
if name == 'name' then names[#names+1] = data:match('>(.-)<', c) end
if name == 'price' then prices[#prices+1] = data:match('>(.-)<', c) end
end})
p:parse(data)
p:close()
print('Name: ', table.concat(names, ', '))
print('Price: ', table.concat(prices, ', '))
Output:
<item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> Name: Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets Price: 14.50, 23.99, 4.95, 3.56
Mathematica/Wolfram Language
example = Import["test.txt", "XML"];
Cases[example, XMLElement["item", _ , _] , Infinity] // First
Cases[example, XMLElement["price", _, List[n_]] -> n, Infinity] // Column
Cases[example, XMLElement["name", _, List[n_]] -> n, Infinity] // Column
- Output:
XMLElement[item,{upc->123456789,stock->12}, {XMLElement[name,{},{Invisibility Cream}],XMLElement[price,{},{14.50}],XMLElement[description,{},{Makes you invisible}]}] 14.50 23.99 4.95 3.56 Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
NetRexx
/* NetRexx */
options replace format comments java symbols binary
import javax.xml.parsers.
import javax.xml.xpath.
import org.w3c.dom.
import org.w3c.dom.Node
import org.xml.sax.
xmlStr = '' -
|| '<inventory title="OmniCorp Store #45x10^3">' -
|| ' <section name="health">' -
|| ' <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>' -
|| ' </section>' -
|| ' <section name="food">' -
|| ' <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 priwater</description>' -
|| ' </item>' -
|| ' </section>' -
|| '</inventory>'
expr1 = '/inventory/section/item[1]'
expr2 = '/inventory/section/item/price'
expr3 = '/inventory/section/item/name'
attr1 = 'upc'
do
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xmlStr)))
xpath = XPathFactory.newInstance().newXPath()
-- Extract attribute from 1st item element
say expr1
say " "(Node xpath.evaluate(expr1, doc, XPathConstants.NODE)).getAttributes().getNamedItem(attr1)
say
-- Extract and display all price elments
nodes = NodeList xpath.evaluate(expr2, doc, XPathConstants.NODESET)
say expr2
loop i_ = 0 to nodes.getLength() - 1
say Rexx(nodes.item(i_).getTextContent()).format(10, 2)
end i_
say
-- Extract elements and store in an ArrayList
nameList = java.util.List
nameList = ArrayList()
nodes = NodeList xpath.evaluate(expr3, doc, XPathConstants.NODESET)
loop i_ = 0 to nodes.getLength() - 1
nameList.add(nodes.item(i_).getTextContent())
end i_
-- display contents of ArrayList
say expr3
loop n_ = 0 to nameList.size() - 1
say " "nameList.get(n_)
end n_
say
catch ex = Exception
ex.printStackTrace()
end
return
Output:
/inventory/section/item[1] upc="123456789" /inventory/section/item/price 14.50 23.99 4.95 3.56 /inventory/section/item/name Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
Nim
Nim standard library provides several modules to process XML, but none to process XPath requests. There is no third party library to do that either.
So we provide here a solution which uses the C "libxml2" library. Nim allows to interface with C with a great flexibility. Declaring the external functions is quite easy. The major part of the work consists to declare the data types. In "libxml2" there are a lot of structures and we have translated only what is needed to solve the task (or actually a bit more).
For the first request, we use //section[1]/item[1]
instead of //item[1]
(this is also what the Python version does). The latter request works but it returns the first element in each section which doesn’t seem to be what is expected.
import sequtils, strutils
const LibXml = "libxml2.so"
type
XmlDocPtr = pointer
XmlXPathContextPtr = pointer
XmlElementKind = enum
xmlElementNode = 1
xmlAttributeNode = 2
xmlTextNode = 3
xmlCdataSectionNode = 4
xmlEntityRefNode = 5
xmlEntityNode = 6
xmlPiNode = 7
xmlCommentNode = 8
xmlDocumentNode = 9
xmlDocumentTypeNode = 10
xmlDocumentFragNode = 11
xmlNotationNode = 12
xmlHtmlDocumentNode = 13
xmlDtdNode = 14
xmlElementDecl = 15
xmlAttributeDecl = 16
xmlEntityDecl = 17
xmlNamespaceDecl = 18
xmlXincludeStart = 19
xmlXincludeEnd = 20
XmlNsKind = XmlElementKind
XmlNsPtr = ptr XmlNs
XmlNs = object
next: XmlNsPtr
kind: XmlNsKind
href: cstring
prefix: cstring
private: pointer
context: XmlDocPtr
XmlAttrPtr = pointer
XmlNodePtr = ptr XmlNode
XmlNode = object
private: pointer
kind: XmlElementKind
name: cstring
children: XmlNodePtr
last: XmlNodePtr
parent: XmlNodePtr
next: XmlNodePtr
prev: XmlNodePtr
doc: XmlDocPtr
ns: XmlNsPtr
content: cstring
properties: XmlAttrPtr
nsDef: XmlNsPtr
psvi: pointer
line: cushort
extra: cushort
XmlNodeSetPtr = ptr XmlNodeSet
XmlNodeSet = object
nodeNr: cint
nodeMax: cint
nodeTab: ptr UncheckedArray[XmlNodePtr]
XmlPathObjectKind = enum
xpathUndefined
xpathNodeset
xpathBoolean
xpathNumber
xpathString
xpathPoint
xpathRange
xpathLocationset
xpathUsers
xpathXsltTree
XmlXPathObjectPtr = ptr XmlXPathObject
XmlXPathObject = object
kind: XmlPathObjectKind
nodeSetVal: XmlNodeSetPtr
boolVal: cint
floatVal: cdouble
stringVal: cstring
user: pointer
index: cint
user2: pointer
index2: cint
XmlSaveCtxtPtr = pointer
XmlBufferPtr = pointer
# Declaration of needed "libxml2" procedures.
proc xmlParseFile(docName: cstring): XmlDocPtr
{.cdecl, dynlib: LibXml, importc: "xmlParseFile".}
proc xmlXPathNewContext(doc: XmlDocPtr): XmlXPathContextPtr
{.cdecl, dynlib: LibXml, importc: "xmlXPathNewContext".}
proc xmlXPathEvalExpression(str: cstring; ctxt: XmlXPathContextPtr): XmlXPathObjectPtr
{.cdecl, dynlib: LibXml, importc: "xmlXPathEvalExpression".}
proc xmlXPathFreeContext(ctxt: XmlXPathContextPtr)
{.cdecl, dynlib: LibXml, importc: "xmlXPathFreeContext".}
proc xmlXPathFreeObject(obj: XmlXPathObjectPtr)
{.cdecl, dynlib: LibXml, importc: "xmlXPathFreeObject".}
proc xmlSaveToBuffer(vuffer: XmlBufferPtr; encoding: cstring; options: cint): XmlSaveCtxtPtr
{.cdecl, dynlib: LibXml, importc: "xmlSaveToBuffer".}
proc xmlBufferCreate(): XmlBufferPtr
{.cdecl, dynlib: LibXml, importc: "xmlBufferCreate".}
proc xmlBufferFree(buf: XmlBufferPtr)
{.cdecl, dynlib: LibXml, importc: "xmlBufferCreate".}
proc xmlBufferContent(buf: XmlBufferPtr): cstring
{.cdecl, dynlib: LibXml, importc: "xmlBufferContent".}
proc xmlSaveTree(ctxt: XmlSaveCtxtPtr; cur: XmlNodePtr): clong
{.cdecl, dynlib: LibXml, importc: "xmlSaveTree".}
proc xmlSaveClose(ctxt: XmlSaveCtxtPtr)
{.cdecl, dynlib: LibXml, importc: "xmlSaveClose".}
proc `$`(node: XmlNodePtr): string =
## Return the representation of a node.
let buffer = xmlBufferCreate()
let saveContext = xmlSaveToBuffer(buffer, nil, 0)
discard saveContext.xmlSaveTree(node)
saveContext.xmlSaveClose()
result = $buffer.xmlBufferContent()
xmlBufferFree(buffer)
iterator nodes(xpath: string; context: XmlXPathContextPtr): XmlNodePtr =
## Yield the nodes which fit the XPath request.
let xpathObj = xmlXPathEvalExpression(xpath, context)
if xpathObj.isNil:
quit "Failed to evaluate XPath: " & xpath, QuitFailure
assert xpathObj.kind == xpathNodeset
let nodeSet = xpathObj.nodeSetVal
if not nodeSet.isNil:
for i in 0..<nodeSet.nodeNr:
yield nodeSet.nodeTab[i]
xmlXPathFreeObject(xpathObj)
# Load and parse XML file.
let doc = xmlParseFile("xpath_test.xml")
if doc.isNil:
quit "Unable to load and parse document", QuitFailure
# Create an XPath context.
let context = xmlXPathNewContext(doc)
if context.isNil:
quit "Failed to create XPath context", QuitFailure
var xpath = "//section[1]/item[1]"
echo "Request $#:".format(xpath)
for node in nodes(xpath, context):
echo node
echo()
xpath = "//price/text()"
echo "Request $#:".format(xpath)
for node in nodes(xpath, context):
echo node.content
echo()
xpath = "//name"
echo "Request $#:".format(xpath)
let names = toSeq(nodes(xpath, context)).mapIt(it.children.content)
echo names
xmlXPathFreeContext(context)
- Output:
Request //section[1]/item[1]: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> Request //price/text(): 14.50 23.99 4.95 3.56 Request //name: @["Invisibility Cream", "Levitation Salve", "Blork and Freen Instameal", "Grob winglets"]
Objeck
XPath is used to fetch element tags.
use XML;
bundle Default {
class Test {
function : Main(args : String[]) ~ Nil {
in := String->New();
in->Append("<inventory title=\"OmniCorp Store #45x10^3\">");
in->Append("<section name=\"health\">");
in->Append("<item upc=\"123456789\" stock=\"12\">");
in->Append("<name>Invisibility Cream</name>");
in->Append("<price>14.50</price>");
in->Append("<description>Makes you invisible</description>");
in->Append("</item>");
in->Append("<item upc=\"445322344\" stock=\"18\">");
in->Append("<name>Levitation Salve</name>");
in->Append("<price>23.99</price>");
in->Append("<description>Levitate yourself for up to 3 hours per application</description>");
in->Append("</item>");
in->Append("</section>");
in->Append("<section name=\"food\">");
in->Append("<item upc=\"485672034\" stock=\"653\">");
in->Append("<name>Blork and Freen Instameal</name>");
in->Append("<price>4.95</price>");
in->Append("<description>A tasty meal in a tablet; just add water</description>");
in->Append("</item>");
in->Append("<item upc=\"132957764\" stock=\"44\">");
in->Append("<name>Grob winglets</name>");
in->Append("<price>3.56</price>");
in->Append("<description>Tender winglets of Grob. Just add water</description>");
in->Append("</item>");
in->Append("</section>");
in->Append("</inventory>");
parser := XmlParser->New(in);
if(parser->Parse()) {
# get first item
results := parser->FindElements("//inventory/section[1]/item[1]");
if(results <> Nil) {
IO.Console->Instance()->Print("items: ")->PrintLine(results->Size());
};
# get all prices
results := parser->FindElements("//inventory/section/item/price");
if(results <> Nil) {
each(i : results) {
element := results->Get(i)->As(XMLElement);
element->GetContent()->PrintLine();
};
};
# get names
results := parser->FindElements("//inventory/section/item/name");
if(results <> Nil) {
IO.Console->Instance()->Print("names: ")->PrintLine(results->Size());
};
};
}
}
}
Oz
We implement a small subset of XPath for this task:
declare
[XMLParser] = {Module.link ['x-oz://system/xml/Parser.ozf']}
proc {Main Data}
Parser = {New XMLParser.parser init}
[Doc] = {Parser parseVS(Data $)}
FirstItem = {XPath Doc [inventory section item]}.1
Prices = {XPath Doc [inventory section item price Text]}
Names = {XPath Doc [inventory section item name]}
in
{ForAll Prices System.showInfo}
end
%%
%% Emulation of some XPath functionality:
%%
fun {XPath Doc Path}
P|Pr = Path
in
Doc.name = P %% assert
{FoldL Pr XPathStep [Doc]}
end
fun {XPathStep Elements P}
if {IsProcedure P} then
{Map Elements P}
else
{FilteredChildren Elements P}
end
end
%% A flat list of all Type-children of all Elements.
fun {FilteredChildren Elements Type}
{Flatten
{Map Elements
fun {$ E}
{Filter E.children
fun {$ X}
case X of element(name:!Type ...) then true
else false
end
end}
end}}
end
%% PCDATA of an element as a ByteString
fun {Text Element}
Texts = for Child in Element.children collect:C do
case Child of text(data:BS ...) then {C BS} end
end
in
{FoldR Texts ByteString.append {ByteString.make nil}}
end
Data =
"<inventory title=\"OmniCorp Store #45x10^3\">"
#" <section name=\"health\">"
#" <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>"
#" </section>"
#" <section name=\"food\">"
#" <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>"
#" </section>"
#"</inventory>"
in
{Main Data}
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;
Phix
Phix has no direct support for XPath, but achieving the requirements using the standard xml_parse() is not exactly difficult.
include builtins/xml.e constant xml_txt = """ <inventory title="OmniCorp Store #45x10^3"> <section name="health"> <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> </section> <section name="food"> <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> </section> </inventory> """, -- or, of course, xml_txt = get_text("input.xml") xml = xml_parse(xml_txt) sequence sections = xml_get_nodes(xml[XML_CONTENTS],"section"), item1 = {}, prices = {}, names = {} for s=1 to length(sections) do sequence items = xml_get_nodes(sections[s],"item") if item1={} then item1 = items[1] end if for i=1 to length(items) do prices = append(prices,xml_get_nodes(items[i],"price")[1][XML_CONTENTS]) names = append(names,xml_get_nodes(items[i],"name")[1][XML_CONTENTS]) end for end for puts(1,"===item[1]===\n") sequence tmp = xml_new_doc(item1) puts(1,xml_sprint(tmp)) puts(1,"===prices===\n") pp(prices) puts(1,"===names===\n") pp(names,{pp_Maxlen,90})
- Output:
===item[1]=== <?xml version="1.0" encoding="utf-8" ?> <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> ===prices=== {`14.50`, `23.99`, `4.95`, `3.56`} ===names=== {`Invisibility Cream`, `Levitation Salve`, `Blork and Freen Instameal`, `Grob winglets`}
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;
}
PicoLisp
(load "@lib/xm.l")
(let Sections (body (in "file.xml" (xml)))
(pretty (car (body (car Sections))))
(prinl)
(for S Sections
(for L (body S)
(prinl (car (body L 'price))) ) )
(make
(for S Sections
(for L (body S)
(link (car (body L 'name))) ) ) ) )
Output:
(item ((upc . "123456789") (stock . "12")) (name NIL "Invisibility Cream") (price NIL "14.50") (description NIL "Makes you invisible") ) 14.50 23.99 4.95 3.56 -> ("Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets")
PowerShell
Cast the $document
string as [xml]
and you have access to .NET methods affecting XML.
$document = [xml]@'
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
'@
$query = "/inventory/section/item"
$items = $document.SelectNodes($query)
The first item:
$items[0]
- Output:
upc : 123456789 stock : 12 name : Invisibility Cream price : 14.50 description : Makes you invisible
Get some useful information:
$namesAndPrices = $items | Select-Object -Property name, price
$namesAndPrices
- Output:
name price ---- ----- Invisibility Cream 14.50 Levitation Salve 23.99 Blork and Freen Instameal 4.95 Grob winglets 3.56
Here are the prices:
$items.price
- Output:
14.50 23.99 4.95 3.56
Here are the names:
$items.name
- Output:
Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
Python
# Python has basic xml parsing built in
from xml.dom import minidom
xmlfile = file("test3.xml") # load xml document from file
xmldoc = minidom.parse(xmlfile).documentElement # parse from file stream or...
xmldoc = minidom.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")
In Python 2.5+ you can use ElementTree's limited XPath support
import xml.etree.ElementTree as ET
xml = open('inventory.xml').read()
doc = ET.fromstring(xml)
doc = ET.parse('inventory.xml') # or load it directly
# Note, ElementTree's root is the top level element. So you need ".//" to really start searching from top
# Return first Item
item1 = doc.find("section/item") # or ".//item"
# Print each price
for p in doc.findall("section/item/price"): # or ".//price"
print "{0:0.2f}".format(float(p.text)) # could raise exception on missing text or invalid float() conversion
# list of names
names = doc.findall("section/item/name") # or ".//name"
Or, you can install the lxml package and get full XPath support
from lxml import etree
xml = open('inventory.xml').read()
doc = etree.fromstring(xml)
doc = etree.parse('inventory.xml') # or load it directly
# Return first item
item1 = doc.xpath("//section[1]/item[1]")
# Print each price
for p in doc.xpath("//price"):
print "{0:0.2f}".format(float(p.text)) # could raise exception on missing text or invalid float() conversion
names = doc.xpath("//name") # list of names
R
library("XML")
doc <- xmlInternalTreeParse("test3.xml")
# Retrieve the first "item" element
getNodeSet(doc, "//item")[[1]]
# Perform an action on each "price" element
sapply(getNodeSet(doc, "//price"), xmlValue)
# Get an array of all the "name" elements
sapply(getNodeSet(doc, "//name"), xmlValue)
Racket
#lang at-exp racket
(define input @~a{
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>})
(require xml xml/path)
(define data (xml->xexpr
((eliminate-whitespace '(inventory section item))
(read-xml/element (open-input-string input)))))
;; Retrieve the first "item" element
(displayln (xexpr->string (se-path* '(item) data)))
;; => <name>Invisibility Cream</name>
;; Perform an action on each "price" element (print it out)
(printf "Prices: ~a\n" (string-join (se-path*/list '(item price) data) ", "))
;; => Prices: 14.50, 23.99, 4.95, 3.56
;; Get an array of all the "name" elements
(se-path*/list '(item name) data)
;; => '("Invisibility Cream" "Levitation Salve" "Blork and Freen Instameal" "Grob winglets")
Raku
(formerly Perl 6)
use XML::XPath;
my $XML = XML::XPath.new(xml => q:to/END/);
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
END
put "First item:\n", $XML.find('//item[1]')[0];
put "\nPrice elements:";
.contents.put for $XML.find('//price').List;
put "\nName elements:\n", $XML.find('//name')».contents.join: ', ';
- Output:
First item: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> Price elements: 14.50 23.99 4.95 3.56 Name elements: Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets
Rascal
import lang::xml::DOM;
import Prelude;
public void get_first_item(loc a){
D = parseXMLDOM(readFile(a));
top-down-break visit(D){
case E:element(_,"item",_): return println(xmlPretty(E));
};
}
public void print_prices(loc a){
D = parseXMLDOM(readFile(a));
for(/element(_,"price",[charData(/str p)]) := D)
println(p);
}
public list[str] get_names(loc a){
D = parseXMLDOM(readFile(a));
L = [];
for(/element(_,"name",[charData(/str n)]) := D)
L += n;
return L;
}
Example output:
rascal>get_first_item(|file:///Users/.../Desktop/xmlpath.xml|)
<?xml version="1.0" encoding="UTF-8"?>
<item stock="12" upc="123456789">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>
ok
rascal>print_prices(|file:///Users/.../Desktop/xmlpath.xml|)
14.50
23.99
4.95
3.56
ok
rascal>get_names(|file:///Users/.../Desktop/xmlpath.xml|)
list[str]: ["Invisibility Cream","Levitation Salve","Blork and Freen Instameal","Grob winglets"]
REXX
hard coded parsing
/*REXX program to parse various queries on an XML document (from a file). */
iFID='XPATH.XML' /*name of the input XML file (doc). */
$= /*string will contain the file's text. */
do j=1 while lines(iFID)\==0 /*read the entire file into a string. */
$=$ linein(iFID) /*append the line to the $ string. */
end /*j*/
/* [↓] show 1st ITEM in the document*/
parse var $ '<item ' item "</item>"
say center('first item:',length(space(item)),'─') /*display a nice header.*/
say space(item)
/* [↓] show all PRICES in the document*/
prices= /*nullify the list and add/append to it*/
$$=$ /*start with a fresh copy of document. */
do until $$='' /* [↓] keep parsing string until done.*/
parse var $$ '<price>' price '</price>' $$
prices=prices price /*add/append the price to the list. */
end /*until*/
say
say center('prices:',length(space(prices)),'─') /*display a nice header.*/
say space(prices)
/* [↓] show all NAMES in the document*/
names.= /*nullify the list and add/append to it*/
L=length(' names: ') /*maximum length of any one list name. */
$$=$ /*start with a fresh copy of document. */
do #=1 until $$='' /* [↓] keep parsing string until done.*/
parse var $$ '<name>' names.# '</name>' $$
L=max(L,length(names.#)) /*L: is used to find the widest name. */
end /*#*/
names.0=#-1; say /*adjust the number of names (DO loop).*/
say center('names:',L,'─') /*display a nicely formatted header. */
do k=1 for names.0 /*display all the names in the list. */
say names.k /*display a name from the NAMES list.*/
end /*k*/
/*stick a fork in it, we're all done. */
output
──────────────────────────────────────────────────────────first item:────────────────────────────────────────────────────────── upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> ───────prices:─────── 14.50 23.99 4.95 3.56 ─────────names:────────── Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
generic parsing
/*REXX program to parse various queries on an XML document (from a file). */
iFID='XPATH.XML' /*name of the input XML file (doc). */
$= /*string will contain the file's text. */
do j=1 while lines(iFID)\==0 /*read the entire file into a string. */
$=$ linein(iFID) /*append the line to the $ string. */
end /*j*/
/* [↓] display 1st ITEM in document. */
call parser 'item', 0 /*go and parse the all the ITEMs. */
say center('first item:',@L.1,'─') /*display a nicely formatted header. */
say @.1; say /*display the first ITEM found. */
call parser 'price' /*go and parse all the PRICEs. */
say center('prices:',length(@@@),'─') /*display a nicely formatted header. */
say @@@; say /*display a list of all the prices. */
call parser 'name'
say center('names:',@L,'─') /*display a nicely formatted header. */
do k=1 for # /*display all the names in the list. */
say @.k /*display a name from the NAMES list.*/
end /*k*/
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
parser: parse arg yy,tail,,@. @@. @@@; $$=$; @L=9; yb='<'yy; ye='</'yy">"
tail=word(tail 1, 1) /*use a tail ">" or not?*/
do #=1 until $$='' /*parse complete XML doc. */
if tail then parse var $$ (yb) '>' @@.# (ye) $$ /*find meat.*/
else parse var $$ (yb) @@.# (ye) $$ /* " " */
@.#=space(@@.#); @@@=space(@@@ @.#) /*shrink; @@@=list of YY.*/
@L.#=length(@.#); @L=max(@L,@L.#) /*length; maximum length. */
end /*#*/
#=#-1 /*adjust # of thing found.*/
return
output is the same as the 1st version.
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" )
Scala
The code is entered in to Scala's REPL, to better show the results.
scala> val xml: scala.xml.Elem =
| <inventory title="OmniCorp Store #45x10^3">
| <section name="health">
| <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>
| </section>
| <section name="food">
| <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>
| </section>
| </inventory>
scala> val firstItem = xml \\ "item" take 1
firstItem: scala.xml.NodeSeq =
NodeSeq(<item upc="123456789" stock="12">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>)
scala> xml \\ "price" map (_.text) foreach println
14.50
23.99
4.95
3.56
scala> val names = (xml \\ "name").toArray
names: Array[scala.xml.Node] = Array(<name>Invisibility Cream</name>, <name>Levitation Salve</name>, <name>Blork and Freen Instameal</name>, <name>Grob winglets</name>)
SenseTalk
Set XMLSource to {{
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
}}
put node "//item[1]" of XMLSource
put node "//price/text()" of XMLSource
put all nodes "//name" of XMLSource
- Output:
<item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> 14.50 (<name>Invisibility Cream</name>,<name>Levitation Salve</name>,<name>Blork and Freen Instameal</name>,<name>Grob winglets</name>)
Sidef
require('XML::XPath');
var x = %s'XML::XPath'.new(ARGF.slurp);
[x.findnodes('//item[1]')][0];
say [x.findnodes('//price')].map{x.getNodeText(_)};
[x.findnodes('//name')];
- Output:
[14.5, 23.99, 4.95, 3.56]
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]
}
TUSCRIPT
$$ MODE TUSCRIPT,{}
MODE DATA
$$ XML=*
<inventory title="OmniCorp Store #45x10³">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
$$ MODE TUSCRIPT
FILE = "test.xml"
ERROR/STOP CREATE (file,fdf-o,-std-)
FILE/ERASE/UTF8 $FILE = xml
BUILD S_TABLE beg=":<item*>:<name>:<price>:"
BUILD S_TABLE end=":</item>:</name>:</price>:"
BUILD S_TABLE modifiedbeg=":<name>:<price>:"
BUILD S_TABLE modifiedend=":</name>:</price>:"
firstitem=names="",countitem=0
ACCESS q: READ/STREAM/UTF8 $FILE s,a/beg+t+e/end
LOOP
READ/EXIT q
IF (a=="<name>") names=APPEND(names,t)
IF (a=="<price>") PRINT t
IF (a.sw."<item") countitem=1
IF (countitem==1) THEN
firstitem=CONCAT(firstitem,a)
firstitem=CONCAT(firstitem,t)
firstitem=CONCAT(firstitem,e)
IF (e=="</item>") THEN
COUNTITEM=0
MODIFY ACCESS q s_TABLE modifiedbeg,-,modifiedend
ENDIF
ENDIF
ENDLOOP
ENDACCESS q
ERROR/STOP CLOSE (file)
firstitem=EXCHANGE (firstitem,":{2-00} ::")
firstitem=INDENT_TAGS (firstitem,-," ")
names=SPLIT(names)
TRACE *firstitem,names
Output:
14.50 23.99 4.95 3.56 TRACE * 63 -*TUSTEP.EDT firstitem = * 1 = <item upc="123456789" stock="12"> 2 = <name>Invisibility Cream</name> 3 = <price>14.50</price> 4 = <description>Makes you invisible</description> 5 = </item> names = * 1 = Invisibility Cream 2 = Levitation Salve 3 = Blork and Freen Instameal 4 = Grob winglets
VBScript
Set objXMLDoc = CreateObject("msxml2.domdocument")
objXMLDoc.load("In.xml")
Set item_nodes = objXMLDoc.selectNodes("//item")
i = 1
For Each item In item_nodes
If i = 1 Then
WScript.StdOut.Write item.xml
WScript.StdOut.WriteBlankLines(2)
Exit For
End If
Next
Set price_nodes = objXMLDoc.selectNodes("//price")
list_price = ""
For Each price In price_nodes
list_price = list_price & price.text & ", "
Next
WScript.StdOut.Write list_price
WScript.StdOut.WriteBlankLines(2)
Set name_nodes = objXMLDoc.selectNodes("//name")
list_name = ""
For Each name In name_nodes
list_name = list_name & name.text & ", "
Next
WScript.StdOut.Write list_name
WScript.StdOut.WriteBlankLines(2)
- Output:
<item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> 14.50, 23.99, 4.95, 3.56, Invisibility Cream, Levitation Salve, Blork and Freen Instameal, Grob winglets,
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
Wren
Wren does not have built-in support for XML/XPath and, to my knowledge, there is no third party module which adds such support either. We therefore have to fall back on string pattern matching to perform the required queries.
import "./pattern" for Pattern
var doc = """
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
"""
var p1 = Pattern.new("<item ")
var match1 = p1.find(doc)
var p2 = Pattern.new("<//item>")
var match2 = p2.find(doc)
System.print("The first 'item' element is:")
System.print(" " + doc[match1.index..match2.index + 6])
var p3 = Pattern.new("<price>[+1^<]<//price>")
var matches = p3.findAll(doc)
System.print("\nThe 'prices' are:")
for (m in matches) System.print(m.captures[0].text)
var p4 = Pattern.new("<name>[+1^<]<//name>")
var matches2 = p4.findAll(doc)
var names = matches2.map { |m| m.captures[0].text }.toList
System.print("\nThe 'names' are:")
System.print(names.join("\n"))
- Output:
The first 'item' element is: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> The 'prices' are: 14.50 23.99 4.95 3.56 The 'names' are: Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
Since the first version was written, the above XML parser has appeared. Consequently, the solution can now be rewritten as follows, the output being the same as before.
Note that this library doesn't support XPath as such though for this particular task simple 'for' statements suffice.
import "./xsequence" for XDocument
var xml = """
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<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>
</section>
<section name="food">
<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>
</section>
</inventory>
"""
var doc = XDocument.parse(xml)
System.print("The first 'item' element is:")
System.print(doc.root.element("section").element("item"))
var prices = []
var names = []
for (el in doc.root.elements) {
for (el2 in el.elements) {
prices.add(el2.element("price").value)
names.add(el2.element("name").value)
}
}
System.print("\nThe 'prices' are:\n%(prices.join("\n"))")
System.print("\nThe 'names' are:\n%(names.join("\n"))")
XPL0
To run: xml <xml.xml
include xpllib; \for StrFind
char XML(1000000), P, P1, P2, Addr;
int I, Ch;
[I:= 0;
loop [Ch:= ChIn(1);
XML(I):= Ch;
if Ch = $1A \EOF\ then quit;
I:= I+1;
];
XML(I):= 0;
P1:= StrFind(XML, "<item ");
P2:= StrFind(XML, "</item>");
Text(0, "The first 'item' element is:^m^j");
for P:= P1 to P2+6 do ChOut(0, P(0));
CrLf(0);
Text(0, "^m^jThe 'prices' are:^m^j");
Addr:= XML;
loop [P1:= StrFind(Addr, "<price>");
if P1 = 0 then quit;
P2:= StrFind(Addr, "</price>");
if P2 = 0 then quit;
for P:= P1+7 to P2-1 do ChOut(0, P(0));
CrLf(0);
Addr:= P2+1;
];
Text(0, "^m^jThe 'names' are:^m^j");
Addr:= XML;
loop [P1:= StrFind(Addr, "<name>");
if P1 = 0 then quit;
P2:= StrFind(Addr, "</name>");
if P2 = 0 then quit;
for P:= P1+6 to P2-1 do ChOut(0, P(0));
CrLf(0);
Addr:= P2+1;
];
]
- Output:
The first 'item' element is: <item upc="123456789" stock="12"> <name>Invisibility Cream</name> <price>14.50</price> <description>Makes you invisible</description> </item> The 'prices' are: 14.50 23.99 4.95 3.56 The 'names' are: Invisibility Cream Levitation Salve Blork and Freen Instameal Grob winglets
XProc
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc"
name="one-two-three"
version="1.0">
<p:identity>
<p:input port="source">
<p:inline>
<root>
<first/>
<prices/>
<names/>
</root>
</p:inline>
</p:input>
</p:identity>
<p:insert match="/root/first" position="first-child">
<p:input port="insertion" select="(//item)[1]">
<p:pipe port="source" step="one-two-three"/>
</p:input>
</p:insert>
<p:insert match="/root/prices" position="first-child">
<p:input port="insertion" select="//price">
<p:pipe port="source" step="one-two-three"/>
</p:input>
</p:insert>
<p:insert match="/root/names" position="first-child">
<p:input port="insertion" select="//name">
<p:pipe port="source" step="one-two-three"/>
</p:input>
</p:insert>
</p:pipeline>
XQuery
(:
1. Retrieve the first "item" element
Notice the braces around //item. This evaluates first all item elements and then retrieving the first one.
Whithout the braces you get the first item for every section.
:)
let $firstItem := (//item)[1]
(: 2. Perform an action on each "price" element (print it out) :)
let $price := //price/data(.)
(: 3. Get an array of all the "name" elements :)
let $names := //name
return
<result>
<firstItem>{$firstItem}</firstItem>
<prices>{$price}</prices>
<names>{$names}</names>
</result>
Performing this XQuery on the given input document results in
<?xml version="1.0" encoding="UTF-8"?>
<result>
<firstItem>
<item upc="123456789" stock="12">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>
</firstItem>
<prices>14.50 23.99 4.95 3.56</prices>
<names>
<name>Invisibility Cream</name>
<name>Levitation Salve</name>
<name>Blork and Freen Instameal</name>
<name>Grob winglets</name>
</names>
</result>
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>
- Programming Tasks
- XML
- AArch64 Assembly
- AppleScript
- ARM Assembly
- AutoHotkey
- AHK XPath
- Bracmat
- C
- LibXML
- C sharp
- C++
- Caché ObjectScript
- CoffeeScript
- ColdFusion
- Common Lisp
- Plexippus-xpath
- Cxml
- Cxml-stp
- D
- KXML
- Delphi
- E
- E-XML
- Erlang
- Xmerl
- FreeBASIC
- F Sharp
- Factor
- Xml
- Xml.data
- Xml.traversal
- Gastona
- Go
- Xmlpath
- Groovy
- Haskell
- HicEst
- Java
- JavaScript
- Julia
- Kotlin
- Ksh
- Lasso
- LiveCode
- Lua
- Mathematica
- Wolfram Language
- NetRexx
- Nim
- Libxml2
- Objeck
- Oz
- Perl
- Phix
- PHP
- PicoLisp
- PowerShell
- Python
- R
- XML (R)
- Racket
- Raku
- Rascal
- REXX
- Ruby
- REXML
- Scala
- SenseTalk
- Sidef
- Tcl
- TDOM
- TUSCRIPT
- VBScript
- Visual Basic .NET
- Wren
- Wren-pattern
- Wren-xsequence
- XPL0
- XProc
- XQuery
- XSLT
- Batch File/Omit
- PARI/GP/Omit