AMT Help Files

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.

 

begin_definitions
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

 

begin_definitions
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