The ABCs of XML - Part 3: XSLT

This article provides more of what you need to know to survive in the world of connected data by introducing the XSLT programming language, which brings the benefits of XML to industrial automation applications.

2 of 3 1 | 2 | 3 View on one page

The built-in template for element nodes selects child nodes of the current element and tries to find templates that match these children. This built-in behavior results in automatic recursion down every branch of the XML source document tree. There is also a built-in template for text nodes that copies the text to the output. The effect of this built-in template is usually unexpected and unwanted, but can be easily prevented if you understand this behavior.

When a matching template is found for a given node (not a built-in template), the processor will not automatically recurse its children, effectively ending the transformation process for all descendent nodes. The developer may programmatically choose to continue processing child nodes with <xsl:for-each> or by invoking <xsl:apply-templates>, providing fine control of how child nodes are processed.

Output Formatting
The second line of our transform, <xsl:output>, controls output format and must appear before any templates. The attributes specify output formatting instructions for the processor,
 <xsl:output encoding=”utf-8” indent=”yes”/>

In our example, the processor starts with the document root and, finding no matching templates, invokes the built-in template which selects children of the document root and looks again for matching templates. The only child of the document root is the <fhx> element, which is passed to our first template that matches <fhx> elements as children of the document root (identified by the slash).

This template generates a literal <root> element in the output. Inside the <root> element <xsl:apply-templates select=”module”/> invokes the processor to find matching templates for all <module> elements that are children of the current <fhx> element. The processor is instructed to sort the <module> elements in ascending order by the tag attribute of each <module>. The @ prefix identifies an attribute name instead of an element name.

 <xsl:template match=”/fhx”>
   <xsl:apply-templates select=”module”>
    <xsl:sort select=”@tag” data-type=”text”

The processor executes our next template for each <module> element that is a child of the topmost <fhx> element. The module matching template performs a shallow copy of the current <module> element to the output using the <xsl:copy> element. A shallow copy is one that copies a single node without including attributes or descendants. The result is one <module> element in the output for each <module> element in the input. Inside <xsl:copy> are three more XSLT elements. Because these three lie inside the opening and closing <xsl:copy> tags, their results will be output inside the <module> element created by the <xsl:copy> statement. In this way, we can create rich hierarchical output from any type of input XML. The next <xsl:copy-of> element performs a deep copy which includes a copy of all attributes and descendants (children, grandchildren, and so on). The <xsl:copy-of> element includes a select attribute that identifies four elements separated by the pipe (|) operator, which translates as a logical OR. The result is a full copy of <description>, <period>, <controller> or <type> elements that are children of the current <module> element.

The final two statements of our <module> matching template instruct the processor to find matching templates for each of the attributes (@*) of the current <module> element and to find matching templates for each <attribute> element that is a child of the current <module> element. 

 <xsl:template match=”module”>
   <xsl:copy-of select=”description|period|
   <xsl:apply-templates select=”@*”/>
   <xsl:apply-templates select=”attribute”/>

Because Access will not import attributes, the next template must turn these attributes into elements as shown here.

Notice that this template does not specify each attribute by name, but instead processes all <module> attributes irrespective of name or value. Notice how the name() function is used within curly braces {}. The curly braces provide a means for using an expression to create dynamically an attribute value. The expression inside the curly braces is evaluated, converted to a string and the results assigned to the attribute. The name() function returns the name of the current attribute, which is used by the <xsl:element> statement to create an element in the output with the name of the current attribute. The result is an element for each attribute where the new element name matches the name of the corresponding attribute. The <xsl:value-of> element outputs the value of the current attribute as the text content or value for the newly created element completing the transformation from attributes to elements.

 <xsl:template match=”module/@*”>
  <xsl:element name=”{name()}”>
   <xsl:value-of select=”.”/>

The final template creates a single <attribute> element in the output for each <attribute> child of a <module> in the source XML file. This template is a bit more involved, so I won’t dissect it line-by-line. Instead, I’ll describe what is accomplished by this template, and let you figure out how it is achieved. This template must include the following functionality:

2 of 3 1 | 2 | 3 View on one page

Join the discussion

We welcome your thoughtful comments. Please comply with our Community rules.
All comments will display your user name.

Want to participate in the discussion?

Register for free

Log in for complete access.


No one has commented on this page yet.

RSS feed for comments on this page | RSS feed for all comments