XML 101

◷ Reading Time: 11 minutes

Introduction

You can model business logic to process XML data sources:

XML data sources

This processing is not limited to the following logic:

  1. Validate elements existence and values
  2. Validate elements attributes existence and values
  3. Change attributes value
  4. Enrich XML document (e.g., modify, delete, add, etc.) elements and/or attributes

FlexRule Runtime supports XML built-in, and does not require any external library or function.

Loading XML

There are couple of approaches to loading an XML document:

  1. Using parameters type as XML (Explicit XML type).
  2. Using parameters with no type.
  3. Using flow and File activity to load XML from a file.

Define Parameter

To define parameters using FlexRule Designer check Define and Manage Parameters.

Explicit XML Type

When you model a signature (Declaration section) of your logic (i.e., DT, NL, Flow, etc.), you can define a type of XML for a parameter. When you do that, the engine would create an XML document from the parameter value automatically, and then you will be able to use XML monadic operators to manipulate your XML document.

For example:

<DecisionTable name="test">
    <Declaration>
       <Define name="doc" direction="inout" type="xml"/>    </Declaration>
    <!-- ... the rest of your logic goes here ... -->
</DecisionTable>

In the above model, doc will be in an XML type, so all XML monadic operators can be applied automatically. When this approach is taken, then the parameter value can be provided either in a string or a byte array.

If you are using FlexRule Designer, then you can define the XML parameter type by using default types selector.

Build an XML document

Using this method, you can simply have an activity anywhere in your flow to create an XML document. In this scenario, our parameters do not have a type specified. For instance, this might be the result of some other process that has a string representation of an XML document.

For example:

<Flow name="process1" version="1.0.0.0">
  <Declaration>
    <Define name="doc" direction="In" />
  </Declaration>
  <Nodes>
    <Start name="start">
      <Transition name="tr0" to="ActivityCreate"/>
    </Start>
 
    <Activity name="ActivityCreate" expression="doc = doc|toXml()">      <Transition name="tr1" to="ActivityDoSomething"/>
    </Activity>
 
    <Activity name="ActivityDoSomething">
      <Transition name="tr2" to="end"/>
    </Activity>
 
    <End name="end"/>
  </Nodes>
</Flow>

As shown in the above model, in ActivityCreate we build an XML document using |toXml() monad from doc parameter. And after that, we go to the activity ActivityDoSomething, which (for example) can be a Decision Table (or anything else) to process the XML document.

Processing

XML functionality in FlexRule Runtime is very rich. For detailed information, visit XML monadic operators. Here is a summary:

  • Build an XML document (no namespaces): |toXml()
  • Build an XML document and import all namespaces: |toXml(‘ns1’, true) (ns1 here is just an arbitrary value for default namespace prefix.)
  • Query an element: |xmlElement() , |xmlElemenets()
  • Query an attribute: |xmlAttribute(name)
  • Read all values either for the element or attribute: |xmlValue() , |xmlValues()
  • Set a new value either for the element or attribute: |xmlValue(value)
  • Create a new element: |xmlNew()
  • Create a new attribute: |xmlAttribute(name)
  • Read multiple elements: |xmlElements()
  • Read multiple values: |xmlValues()

Sample Expressions

Data

Let’s assume that the following XML is passed to your logic, and an XML document is created using either of above methods. The parameters holding the document are called doc.

 <reports>
  <details>
    <supplier name="A">
      <invoice>
        <invoicenumber>1</invoicenumber>
        <invoicedate>11/09/2003</invoicedate>
        <invoicevalue>402.21</invoicevalue>
      </invoice>
    </supplier>
    <supplier name="B">
      <invoice>
        <invoicenumber>51</invoicenumber>
        <invoicedate>12/08/2009</invoicedate>
        <invoicevalue>164.85</invoicevalue>
      </invoice>
      <invoice>
        <invoicenumber>61</invoicenumber>
        <invoicedate>20/09/2009</invoicedate>
        <invoicevalue>988.65</invoicevalue>
      </invoice>
    </supplier>
  </details>
</reports> 

Expression Examples

Select all suppliers:

doc|xmlElements('//invoicevalue')

Select all suppliers values:

doc|xmlElements('//invoicevalue') |xmlValues() 

Sum of all suppliers invoices values:

doc|xmlElements('//invoicevalue') |xmlValues() |sum()

Namespaces

When the XML document has namespaces, they should be loaded as part of the document. To load namespaces automatically, you should use the expression below to load your XML document and import its XML namespaces:

|toXml(defaultNamespacePrefix, true)

Here is the description of each monad argument:

  • defaultNamespacePrefix: is the prefix for your default XML namespace (xmlns). Specify the default namespace prefix as a string value (i.e., ‘data’). This is mandatory and cannot be left null or empty.
  • true: Tells the XML document it must import its namespaces automatically (always specify true if you want to import the namespaces automatically).

Let’s consider the sample XML below:

 <d:student xmlns:d='http://www.develop.com/student'>
  <d:id>3235329</d:id>  
  <d:name>Jeff Smith</d:name>
  <d:language>C#</d:language>
  <d:rating>35</d:rating>
</d:student> 

And a logic document with the declaration below:

...
<Declaration>
  <Define name="xml" direction="in"/>
</Declaration>
... 

This declaration defines an XML variable parameter with no type.

To load XML with namespace, you should use a parameter with no type approach.

With Default Namespace

Consider your logic has an input parameter called XML with no type specified. Then you can load the XML document as shown below:

xml = xml |toXml('d', true)

This will create an XML document from the XML parameter’s value and import all the namespaces (because the second parameter is set to true). Value d for the first argument of the monad sets the default namespace prefix to d.

Now to query, you simply need to use xpath:

Description xpath Expression
root student element (line #1) //student xml |xmlElement(‘//student’)
id element under root student element (line #2) //student/id xml |xmlElement(‘//student/id’)
value of the id element (text element of line #2) //student/id xml |xmlElement(‘//student/id’) |xmlValue()

The paths do not contain a namespace, because we set d as the default namespace prefix.

No Default Namespace

If the default namespace prefix is not set to d (i.e., in the above XML), then the namespace must be provided in each XPath segment.

For example, on the above XML, let’s create the XML document using the expression below:

xml = xml |toXml('ns1', true)

Now the queries below are using another default namespace prefix:

Description xpath Expression
root student element (line #1) //student xml |xmlElement(‘//d:student’)
id element under root student element (line #2) //d:student/d:id xml |xmlElement(‘//d:student/d:id’)
value of the id element (text element of line #2) //d:student/d:id xml |xmlElement(‘//d:student/d:id’) |xmlValue()

This will set the default namespace prefix to ns1. Therefore all paths segments must have d prefix.

Removing namespaces

If the document contains multiple namespaces in different tags, first you have to remove all the namespaces in order to access the elements.

This will remove the namespaces:

xml = xml|xmlPlain()

Let’s consider the sample XML below:

<d:student xmlns:d='http://www.develop.com/student'>
  <id>3235329</id>  
  <name>Jeff Smith</name>
  <a:language xmlns:a='http://www.develop.com/language'>C#</a:language>
  <rating>35</rating>
</d:student> 

And after removing the namespaces the output will be:

<student>
  <id>3235329</id>  
  <name>Jeff Smith</name>
  <language>C#</language>
  <rating>35</rating>
</student> 

After that, you can use the XML functions to access the values in the XML object.

Sample Project

In this scenario, we want to calculate the Discount for a collection of books and then add a Discount element to each individual book. We will use the following:

  1. toXml: to load XML document
  2. xmlElement: to access different elements using XPath address
  3. xmlValue:
    1. to read the value of a quantity element
    2. to set the value of a discount element
  4. xmlNew: to create a new XML element

Download

Download an XML sample project (Xml-Sample.zip) using the attachment at the end of the page.

Sample main flow

No Type
  1. Using Parameters(no type).xml accepts a parameter called XML with no defined type.
  2. The first step of the flow creates an XML document from its content (XML string).
  3. Then it calculates the discount for all of the books in the XML document.
Explicit Type
  1. Using Parameters(xml).xml accepts a parameter called XML with the explicit type set to XML.
  2. The first step of the flow creates an XML document from its content (XML string).
  3. Then it calculates a discount for all the books in the XML document.

As you can see, the flow for the Explicit type is smaller (has fewer nodes), because the value that is going to be passed as an input parameter to this flow will create the XML document automatically. This is because the type of parameter is set to XML. In the other scenario, however, the type is not set. So there needs to be one more step in order to create an XML document using the input parameter’s value.

Running sample

Use Run Template that has the sample data, and then press Debug to run the flow step by step.

Updated on October 30, 2023

Article Attachments

Was this article helpful?

Related Articles