XML examples
On this page a report will be shown where an XML file is created with values from a database and then a
report where that XML is consumed into a database.
The purpose of these reports is to give you an idea of most XML
functions that are available in AMT.
For examples of XML with namespaces please see: Producing XML with Namespaces & Consuming XML with Namespaces.
const
var
xml_document : xml
xml_root : xmlnode
xml_node1 : xmlnode
xml_node2 : xmlnode
xml_node3 : xmlnode
path : string
xml_as_string : string
tq_cust : tablequery (t_customers)
booleans
end_definitions
routine main
begin_routine
// First the declaration is set and the root node is added.
xml_document.setxmldeclaration ('1.0','utf-8')
xml_root := xml_document.add ('Customers')
// A table query loop is used to add each customer's values to the xml nodes and child nodes.
tq_cust.index (idx_customers)
loop tq_cust
// Per Customer a node is added to the root.
xml_node1 := xml_root.add ('Customer')
// This Customer node then has 5 child nodes added to it.
xml_node2 := xml_node1.add ('CustomerNumber')
xml_node2.value := tq_cust.custno
xml_node2 := xml_node1.add ('Name')
xml_node2.value := tq_cust.custname
xml_node2 := xml_node1.add ('Address')
xml_node2.value := tq_cust.custaddress
xml_node2 := xml_node1.add ('City')
xml_node2.value := tq_cust.custcity
xml_node2 := xml_node1.add ('Accounts')
// The 'Accounts' node has its own child nodes
// with an attribute to show what type of account it is.
if tq_cust.depaccnr <> ''
xml_node3 := xml_node2.add ('Account')
xml_node3.value := tq_cust.depaccnr
xml_node3.attribute.add ('Type','Deposit')
endif
if tq_cust.savsaccnr <> ''
xml_node3 := xml_node2.add ('Account')
xml_node3.value := tq_cust.savsaccnr
xml_node3.attribute.add ('Type','Savings')
endif
endloop
// After adding all the customer (child) nodes
// and filling them with values from the database,
// the xml document is written to an xml file with the save function.
path := 'BankCustomers.xml'
xml_document.save(path)
// If there was a problem with saving the xml document,
// the system item getlastresult will have complementary information
sme (getlastresult)
// Besides saving the xml document to an xml file,
// it is also possible to assign the xml document to a string.
xml_as_string := xml_document.gettext ()
// After exporting the xml document to both a file and to a string,
// the xml document is cleared from memory so that a new xml document can be created using the same variables.
xml_document.clear ()
end_routine
When used on a database filled with random generated values this results in an XML file with the following structure:
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer>
<CustomerNumber>123546</CustomerNumber>
<Name>Nora
Lucas</Name>
<Address>811 Ridge Street</Address>
<City>Austin</City>
<Accounts>
<Account
Type="Deposit">NL74ABNA0574516842</Account>
<Account
Type="Savings">NL12DLBK0283806315</Account>
</Accounts>
</Customer>
<Customer>
.....
</Customer>
</Customers>
An XML with 8 customers for use with the next report can be downloaded here: BankCustomers.xml
const
var
xml_document : xml
xml_root : xmlnode
xml_node1 : xmlnode
xml_node2 : xmlnode
xml_node3 : xmlnode
xml_nodes : xmlnodes
xml_fc : filecontrol
xml_as_string : string
result_ok : boolean
path : string
hasnextsib : Boolean value true
hasnextsib2 : Boolean value true
tq_cust : tablequery (t_customers)
booleans
end_definitions
routine main
begin_routine
path := 'BankCustomers.xml'
// As alternative method to the load function, the xml file content is read into a string
// Some characters with diacritics are then replaced by characters without diacritics.
// Then the string is parsed as xml document and checked if it is valid.
xml_as_string := xml_fc.givefilecontent (path, -1)
inspect (xml_as_string)
replacing (all, ['é','ä','ç'], ['e','a','c'])
endinspect
xml_document.parse (xml_as_string) RESULTOKTO result_ok
if not result_ok
sme ('Invalid XML file: ', path)
exit
endif
// For completeness the Load function code is also given in a block comment:
{ // Load the XML and check if it is valid.
xml_document.load (path)
if xml_document.filename = ''
sme ('Invalid XML file :', path)
exit
endif }
// Set the root node and the first customer in xml_node1
xml_root := xml_document.root
xml_node1 := xml_root.firstchild
if resok = False
sme ('Empty XML file :', path)
exit
endif
// Loop through all the customer nodes
// do this until there is no next sibling
loop while hasnextsib
// Set the first customer child node in xml_node2
xml_node2:=xml_node1.firstchild
// Loop through all the customer child nodes and
// move the values to the corresponding tablequery fields
// do this until there is no next sibling
loop while hasnextsib2
startcase xml_node2.name
case 'CustomerNumber'
tq_cust.custno := xml_node2.value
case 'Name'
tq_cust.custname := xml_node2.value
case 'Address'
tq_cust.custaddress := xml_node2.value
case 'City'
tq_cust.custcity := xml_node2.value
case 'Accounts'
// Check if there are account child nodes
if xml_node2.haschildnodes
// Set all child nodes of the node Accounts in xml_nodes
// This could also be achieved by using the 'Selectnodes' function
xml_nodes := xml_node2.getelementsbytagname ('Account')
// Loop through the Account nodes in xml_nodes
loop for each xml_node3 in xml_nodes
// If there is exactly one attribute per Account node,
// use it to fill the correct table query field
if xml_node3.attribute.count = 1
if xml_node3.attribute[1].value = 'Deposit'
tq_cust.depaccnr := xml_node3.value
elseif xml_node3.attribute[1].value = 'Savings'
tq_cust.savsaccnr := xml_node3.value
endif
endif
endloop
endif
endcase
// Set the next customer node in xml_node2
// when there is no next node, Set the loop flag to false
xml_node2 := xml_node2.nextsibling
hasnextsib2 := resok
endloop
// After having moved all the values of a customer to the table query
// insert the values into the database if the mandatory customer number field is not zero
// then clear the table query
if tq_cust.custno <> 0 then tq_cust.insert ()
tq_cust.clear ()
// Reset the loop flag for the next customer
hasnextsib2 := true
// Set the next customer in xml_node1
// when there is no next node Set the loop flag to false
xml_node1 := xml_node1.nextsibling
hasnextsib := resok
endloop
sme (path, 'was loaded into the Customer Database')
end_routine