*OBJ/XML |
XML Object |
oHandle=NEW ("*obj/xml" [ , xml_data$ ] )
Where:
xml_data$ |
Optional parameter for the object creation that may contain the XML to be parsed and loaded into the object. (added in PxPlus 2019) |
The "*obj/xml.pvc" object provides a simple means to load/edit/generate XML. It parses the XML into individual node sub-objects where each node can have sub-nodes, attributes and tags.
Internally, the object maintains the XML in a tree structure of 'Node' objects where each node can have a 'Tag$ element (type/name of the node) and a 'Value$ element, which contains the value for that specific node. Each node can also contain subordinate nodes and/or subordinate attributes.
Example:
Consider the following XML example:
<staff>
<employee>
<firstname>John</firstname>
<lastname>Watson</lastname>
</employee>
<employee>
<firstname>Sherlock</firstname>
<lastname>Holmes</lastname>
</employee>
</staff>
When represented using the *obj/xml, this would consist of a node with a 'Tag$ of "staff" containing two subordinate nodes, each with a 'Tag$ of "employee". The first of the subordinate nodes would itself contain two (2) subordinate nodes: the first with a 'Tag$ of "firstname" and a 'Value$ of "John", the second with a 'Tag$ of "lastname" and a 'Value$ of "Watson". The second node of the top-level "staff" node would also contain two subordinates for "Sherlock", "Holmes".
Subordinate nodes can be added to any node using the 'Add_Node( ) method and deleted using the 'Del_Node( ) method.
Nodes may also contain "attribute" nodes, which are used to maintain the attributes of any node. For example, an XML node for <account type="debit"> would have a single attribute node with the 'Tag$ of "type" and a value of "debit".
Attribute nodes may be added to a node using the 'Add_Attr( ) method and deleted using the 'Del_Attr( ) method.
If desired, a node may be loaded using the 'Set_Xml( ) method, which takes XML as a string and builds a node tree from it. The 'Get_Xml$( ) method can also be used on any node to obtain the string representation of the XML within and below that node.
(The XML object *OBJ/XML was added in PxPlus v11.50.)
The following methods are supported:
Method |
Description |
Add_Attr(n) |
Add a new attribute and return its object ID. 'n' defines where to insert the new node (0=Append). |
Add_Attr(tag$) |
Add a new attribute with tag$ specified and return its handle. |
Add_Attr(tag$, n) |
Add a new attribute with tag$ specified after node 'n' and return its handle. |
Add_Node(n) |
Add a new sub-node and return its object ID. 'n' defines where to insert the new node (0=Append). |
Add_Node(n, object) |
Insert the supplied sub node object into the node table after node 'n'. The inserted object will have its reference count incremented, as there will now be an additional reference to it. |
Add_Node(tag$) |
Add a new sub-node with the tag$ specified and return its handle. |
Add_Node(tag$, n) |
Add a new sub-node with the tag$ specified after node 'n' and return the handle of the new node. |
Add_Node(tag$, value$) |
Add a new sub-node with the tag$ and value$ specified and return its handle. |
Add_Node(tag$, value$, n) |
Add a new sub-node with the tag$ and value$ specified after node 'n' and return the handle of the new node. |
Attr(n) |
Return the attribute object 'n'. |
Del_Attr(n) |
Drop the attribute specified. |
Del_Node(n) |
Drop the node specified. |
Find_Index(node) |
Returns the child index of the specified object (Error 11 if not found). |
Find_Node(tag$) |
Find first sub-node whose tag$ matches that specified. Returns 0 if none found. |
Find_Node(tag$, n) |
Find first sub-node whose tag$ matches that specified after node 'n'. Returns 0 if none found. |
Get_Xml$( ) |
Return the XML string from the object and subordinate nodes. |
Next_Sibling( ) |
Returns the node's next sibling (0 if no next sibling). |
Node(n) |
Return the sub node object 'n'. |
Prior_Sibling( ) |
Returns the node's prior sibling (0 if no prior sibling). |
Set_Xml(xml$) |
Load and create nodes given XML string in xml$. This creates a dummy top-level node in which all top-level XML structures are placed. This allows the input XML to contain multiple top-level structures. |
Set_Xml_1(xml$) |
This will load a single node from the XML string and will report an error 42 if it encounters multiples. This avoids the top-level node that may contain multiple nodes. |
Value$(tag$) |
This method will find the specified tag and return its value. Same functionality as 'Find_Node(tag$)'Value$. |
The following properties are supported:
Property |
Description |
attrs |
Number of attributes. |
nodes |
Number of sub-nodes (only direct subordinate nodes). |
parent |
Returns the node's parent (0 if none). |
tag$ |
Node tag (i.e. the <..> keyword). |
value$ |
Text value of the node. |
(The methods Add_Node, Add_Attr, Find_Node and Find_Attr with a tag$ argument were added in PxPlus 2014.)
(The methods Find_Index(node), Next_Sibling( ),Prior_Sibling( ) and the property parent were added in PxPlus 2016.)
(The method Value$(tag$) was added in PxPlus 2019.)
The following code is an example of setting/getting the XML:
x=new("*obj/xml")
x'set_xml("<emp><name>mike king</name><addr>123 main</addr></emp>")
print x'get_xml$()
x'set_xml("<emp><name format='First Last'>mike king</name><addr><street>123 main</street><city>Markham</city></addr></emp>")
print x'get_xml$()
drop object x
You should be able to read the XML file into one long string, invoke set_xml( ), change/edit the nodes, then call get_xml$( ) to retrieve the revised XML back.
Let us assume you have received and need to parse the following XML and have it loaded into the string XML$:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<control>
<status>success</status>
<senderid>JohnDoe</senderid>
<controlid>create_project_simple</controlid>
<uniqueid>false</uniqueid>
<dtdversion>2.1</dtdversion>
</control>
<operation>
<authentication>
<status>success</status>
…more…
To load the XML into the XML object, you would use the 'Set_Xml(string$) method:
-:a=new("*obj/xml") ! Create the object
-:a'set_xml(XML$) ! Pass the XML string
Once loaded, you can parse through all the nodes looking for what you want:
-:?a'node(1)'tag$
?xml
-:?a'node(2)'tag$
response
-:?a'node(2)'node(1)'tag$
control
-:?a'node(2)'node(1)'node(1)'tag$
status
-:?a'node(2)'node(1)'node(1)'value$
success
-:?a'node(2)'node(1)'node(2)'tag$
senderid
-:?a'node(2)'node(1)'node(2)'value$
JohnDoe
You can assign variables to hold the node pointers to make the coding a bit simpler:
-:oResponse=a'node(2)
-:oCtrl=oResponse'node(1)
-:print oCtrl'node(1)'tag$
status
Let us assume you wanted to generate the following XML:
<request>
<login>
<userid>JohnDoe</userid>
<password>drowssap</password>
<database>Sample Corp</database>
</login>
<command>
<create_prod>
<prodcode>000123</prodcode>
<desc>Blue widget</desc>
<price currency='CDN'>1.23</price>
<qty>10</qty>
<uom>ea</uom>
</create_prod>
</command>
</request>
The logic to create this might look like this:
oXml=new("*obj/xml") ! XML Object
oReq=oXml'Add_Node("request")
!
oLogin=oReq'Add_Node("login")
!
oLogin'Add_Node("userid")'value$="JohnDoe"
oLogin'Add_Node("password")'value$="drowssap"
oLogin'Add_Node("database")'value$="Sample_Corp"
!
oCmnd=oReq'Add_Node("command")
!
oCreate=oCmnd'Add_Node("create_prod")
!
oCreate'Add_Node("prodcode")'value$="000123"
oCreate'Add_Node("desc")'value$="Blue Widget"
!
oPrice=oCreate'Add_Node("price")
!
oPrice'value$="1.23"
! -- Add currency
oPrice'Add_Attr("currency")'value$="CDN"
!
oCreate'Add_Node("qty")'value$="10"
oCreate'Add_Node("uom")'value$="ea"
!
x$=oXml'Get_Xml$()
print x$
!
drop object oXml
XML( ) - XML Parsing/Generation Facility