Examples of XSLT
Basic XSLT Techniques
The following examples show the techniques required in most common XSLT transformations:

XSLT—rename elements and attributes
In many cases, elements and attributes have the same semantic meaning in two different DTDs but are named differently. You must therefore create an XSLT script to rename the elements and attributes of one DTD to match the naming conventions in another DTD.
Input stream
The input stream uses the element actor
and attribute role
:
<?xml version="1.0" ?> <actor role="innocent bystander">Peter</actor>
Output stream
The output stream requires the element
person
and attribute type
:
<?xml version="1.0" encoding="UTF-8"?> <person type="innocent bystander">Peter</person>
XSLT stylesheet
Renaming actor
to
person
, and role
to type
, can be done with the
following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="rootTemplate" > <xsl:apply-templates select="actor" /> </xsl:template> <xsl:template match="actor" name="actor-to-person" > <xsl:element name="person"> <xsl:attribute name="type"> <xsl:value-of select="@role" /> </xsl:attribute> <xsl:value-of select="." /> </xsl:element> </xsl:template> </xsl:stylesheet>
Literal result elements
Template actor-to-person
can be
written in a much more compact form, using literal result elements. Literal result elements are any
non-XSLT elements inside a template body. Literal result elements are simply copied to the output
stream by the XSLT processor.
You can also set attribute values for literal
result elements, using curly braces ({ and }) to indicate that the attribute value is not literal,
but derived. These techniques are shown in the following alternative
actor-to-person
template:
<xsl:template match="actor" name="actor-to-person" > <person type="{@role}" > <xsl:value-of select="." /> </person> </xsl:template>

XSLT—rename elements and attributes
In many cases, elements and attributes have the same semantic meaning in two different DTDs but are named differently. You must therefore create an XSLT script to rename the elements and attributes of one DTD to match the naming conventions in another DTD.
Input stream
The input stream uses the element actor
and attribute role
:
<?xml version="1.0" ?> <actor role="innocent bystander">Peter</actor>
Output stream
The output stream requires the element
person
and attribute type
:
<?xml version="1.0" encoding="UTF-8"?> <person type="innocent bystander">Peter</person>
XSLT stylesheet
Renaming actor
to
person
, and role
to type
, can be done with the
following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="rootTemplate" > <xsl:apply-templates select="actor" /> </xsl:template> <xsl:template match="actor" name="actor-to-person" > <xsl:element name="person"> <xsl:attribute name="type"> <xsl:value-of select="@role" /> </xsl:attribute> <xsl:value-of select="." /> </xsl:element> </xsl:template> </xsl:stylesheet>
Literal result elements
Template actor-to-person
can be
written in a much more compact form, using literal result elements. Literal result elements are any
non-XSLT elements inside a template body. Literal result elements are simply copied to the output
stream by the XSLT processor.
You can also set attribute values for literal
result elements, using curly braces ({ and }) to indicate that the attribute value is not literal,
but derived. These techniques are shown in the following alternative
actor-to-person
template:
<xsl:template match="actor" name="actor-to-person" > <person type="{@role}" > <xsl:value-of select="." /> </person> </xsl:template>

XSLT—change attributes to elements
Uniface does not read data from
attributes, with the exception of the processing
information attributes—id
, crc
, status
and
valerr
, which Uniface creates to support disconnected record sets. Therefore, it is almost always necessary to map an attribute to an element before an
xmlload
, and to map an element to an attribute after an xmlsave
.
Input stream
The input stream has an attribute
role
(of the element actor
):
<?xml version="1.0" ?> <actor role="innocent bystander">Peter</actor>
Output stream
The output stream requires elements
type
and name
(as a children of element person
):
<?xml version="1.0" encoding="UTF-8"?> <person> <name>Peter</name> <type>innocent bystander</type> </person>
XSLT stylesheet
Use the following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="root" > <xsl:apply-templates select="actor" /> </xsl:template> <xsl:template match="actor" name="actor-to-person" > <person> <name> <xsl:value-of select="." /> </name> <type> <xsl:value-of select="@role" /> </type> </person> </xsl:template> </xsl:stylesheet>

XSLT—reorder elements
In the simplest case, reordering elements means putting element B before element A. In this example, you are restructuring the tree by creating or removing nodes. This kind of reordering is needed when an attribute is mapped to an element and the text node of the attribute’s element should be mapped to a child element.
Input stream
The following XML stream stores the actor name as
the content of element <actor>
:
<?xml version="1.0" ?> <actor role="innocent bystander">Peter</actor>
Output stream
The output stream requires that the actor name
should be contained in an element <name>
:
<?xml version="1.0" encoding="UTF-8"?> <person> <name>Peter</name> <type>innocent bystander</type> </person>
XSLT stylesheet
Use the following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="root" > <xsl:apply-templates select="actor" /> </xsl:template> <xsl:template match="actor" name="actor-to-person" > <person> <name> <xsl:value-of select="." /> </name> <type> <xsl:value-of select="@role" /> </type> </person> </xsl:template> </xsl:stylesheet>

XSLT—suppress empty elements or attribute
An element always overwrites the value of the field to which it is mapped in Uniface. If no element is mapped to a field, the current value of the field is preserved, even if other fields in the same occurrence are modified by data from the stream. Therefore, it can be useful to exclude empty elements from a stream if you want to preserve default values, or merge subsets of records.
The simplest method is to suppress the output when the source element or attribute is empty.
Input stream
The attribute role
in the
following XML stream should be suppressed in the output stream when it is empty. Otherwise it
should be mapped to the element type
.
<?xml version="1.0" ?> <actors> <actor role="">Peter</actor> <actor role="star">Greta</actor> </actors>
Output stream
The following output is required:
<?xml version="1.0" encoding="UTF-8"?> <persons> <person><name>Peter</name></person> <person><name>Peter</name><type>star</type></person> </persons>
Note: The attribute role
has been
suppressed in the first occurrence of <person>
, while it has been mapped ot
element type
in the second occurrence.
XSLT stylesheet
Use the following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="root" > <persons> <xsl:apply-templates select="//actor" /> </persons> </xsl:template> <xsl:template match="actor[@role=""]"name="supress-output-when-empty" > <person> <name> <xsl:value-of select="." /> </name </person> </xsl:template> <xsl:template match="actor" name="actor-to-person" > <person> <name> <xsl:value-of select="." /> </name> <type> <xsl:value-of select="@role" /> </type> </person> </xsl:template> </xsl:stylesheet>

XSLT—implement exclusive OR relationship
A DTD can specify that it expects element A or element B as a child of another element, but not both. For example, a security implementation only accepts an encrypted password or a codeword, but not both. This constraint is described by the following DTD:
<!ELEMENT security (encryptedpassword | codeword) > <!ELEMENT encryptedpassword ( #PCDATA ) > <!ELEMENT codeword ( #PCDATA ) >
The XSLT stylesheet must be able to either handle
the encryptedpassword
and codeword
elements differently, or
transform them to the same output item. In this example, both of these alternative elements are
transformed to the same output element.
Input stream
The following source XML stream conforms to the DTD:
<?xml version="1.0" ?> <security> <encryptedpassword>4</encryptedpassword> </security>
You should validate the XML stream against the
DTD to confirm the XML stream contains either a password or a codeword. Use ProcScript statement
xmlvalidate
for this purpose.
Output stream
The following output is required:
<?xml version="1.0" encoding="UTF-8"?> <ENTITY.MODEL><FIELD>4</FIELD></ENTITY.MODEL>
Note: This output stream can be loaded by a Uniface component without the need for specifying a mapping between element and field names, if the entity named ENTITY.MODEL is painted on the component, and the ENTITY field list includes a field named FIELD.
XSLT stylesheet
Use the following XSLT stylesheet:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" /> <xsl:template match="/" name="root-template" > <ENTITY.MODEL> <xsl:apply-templates select="security/*" /> </ENTITY.MODEL> </xsl:template> <xsl:template match="encryptedpassword |codeword" name="xor-to-FIELD.ENTITY.MODEL" > <FIELD> <xsl:value-of select="." /> </FIELD> </xsl:template> </xsl:stylesheet>
XSLT applied to Uniface
The following examples show some applications of XSLT within Uniface:

B2B XSLT stylesheets
Uniface uses XSLT stylesheets to transport data to and from B2B messages. cxmlmes2u.xsl converts Ariba B2B messages for processing by Uniface. u2cxmlmes.xsl converts Uniface B2B message into Ariba format. These XSLT stylesheets are provided with your Uniface installation.
These stylesheets also provide examples of the application of XSLT to inter-component communication. This example describes some of the techniques used in these stylesheets.
cxmlmes2u.xsl
This stylesheet removes the need to do default or
local mapping of element names to field names, by transforming the input XML stream to a structure
conforming to Uniface’s default naming structure for elements:
<FIELD.ENTITY.MODEL>
. For example, the following template from
cxmlmes2u.xsl converts attribute domain
to element
<AT_DOMAIN.TCREDENTIAL.U_V8B2B>
:
<xsl:template name="to_domain"> <AT_DOMAIN.TCREDENTIAL.U_V8B2B> <xsl:value-of select="//Header/To/Credential/@domain"/> </AT_DOMAIN.TCREDENTIAL.U_V8B2B> </xsl:template>
The stylesheet uses an identity transformation
template to copy sub-trees from the input XML stream to the output stream. This template applies to
all nodes in the input stream, so if there is no other template with a more exact match for the
current node, the identity transformation template is applied instead (the XSLT standard defines
rules for the precedence of templates, so a template matching a wildcard, such as
"*"
, has lower precedence than a template matching a specific element name, such
as "From"
).
<!-- Identity transformation template --> <xsl:template match="*|@*|comment()|processing-instruction()|text()"> <xsl:copy> <xsl:apply-templates select="*|@*|comment()|processing-instruction()|text()"/> </xsl:copy> </xsl:template> </xsl:transform>
The identity transformation template is particularly useful for B2B stylesheets, because this allows the application to convert and process the B2B envelope, and then process the B2B body in a separate phase.
u2cxmlmes.xsl
XSLT stylesheets are not ’reversible’ so a separate stylesheet is defined to convert the data from the format used by Uniface B2B to a format suitable for Ariba. The following template transfers element values to the attributes required by Ariba:
<!-- Composed element template --> <xsl:template match="CXML.U_V8B2B"> <cXML> <xsl:attribute name="version"> <xsl:value-of select="AT_VERSION/text()"/> </xsl:attribute> <xsl:attribute name="xml:lang"> <xsl:value-of select="AT_LANGUAGE/text()"/> </xsl:attribute> ...

Transform an XML stream
This example uses an XSLT file to
normalize an XML stream so that all the information in the stream can be accessed by the
xmlload
statement. This normalization can be necessary because of the divergence
between the tree structure inherent in XML and the relational model on which Uniface is based. For
more information, see
Uniface-Compliant DTDs.
The input XML stream I_INPUT
has
the following content:
<?xml version="1.0"?> <team id="dfgty4yghr67" crc= "" status="new" > <id>10001</id> <name>Williams</name> <driver id="1223werwr44353456456" crc= "" status="new" age="35" gender="m"> <id>10002</id> <name>Amal</name> </driver> <car id="dyt4645yrhg567" crc= "" status="new" > <id>10003</id> <name>Unknown</name> <manufacturer>Ford</manufacturer> </car> </team>
This stream contains the following information that Uniface cannot load directly into components:
- Information in attributes (such as
age="35"
), which Uniface does not interpret. - The
id
andname
elements occur as the children of elementsteam
,driver
, andcar
. Elements occurring as children of more than one other element are also not supported by Uniface.
Finally, elements team
,
driver
and car
have Uniface processing information attributes
that must be preserved in the output stream.
The target output XML stream,
I_NORMALIZED
is the following (transformed items are in
bold):
<?xml version="1.0" encoding="utf-8" ?> <team crc="" id="dfgty4yghr67" status="new"> <team-id>10001</team-id> <team-name>Williams</team-name> <driver crc="" id="1223werwr44353456456" status="new"> <age>35</age> <gender>m</gender> <driver-id>10002</driver-id> <driver-name>Amal</driver-name> </driver> <car crc="" id="dyt4645yrhg567" status="new"> <car-id>10003</car-id> <car-name>Unknown</car-name> <manufacturer>Ford</manufacturer> </car> </team>
The following XSLT instructions are used to achieve this transformation:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <!-- Copy elements to the output stream. --> <xsl:template match="*" name="main"> <xsl:copy> <!-- The following attributes are to be kept as attributes. --> <!-- First they are copied to the output stream, and then --> <!-- template disableTemplates is applied to the attributes --> <!-- to prevent application of template elementsToAttributes. --> <xsl:copy-of select="@id | @crc | @valerr | @status"/> <!-- Copy elements, rename non-unique elements, convert attributes to elements. --> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Handle attributes by converting them to child elements. --> <xsl:template match="@*" name="elementsToAttributes"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:template> <!-- Make selected element names unique by concatenating parent name. --> <!-- Modify the "match" attribute to change the list of elements --> <!-- requiring concatenation using the XPATH //*/NewName for each element. --> <xsl:template match="//*/name | //*/id" name="concatenateElementNames"> <xsl:element name="{concat(name(..), '-', name())}"> <xsl:value-of select="."/> </xsl:element> </xsl:template> <!-- Disable output of these items, excepting output as the result of an xsl:copy --> <!-- or xsl:copy-of instruction. --> <xsl:template match="@id | @crc | @valerr | @status" name="disableTemplates"/> </xsl:stylesheet>
The following ProcScript can be used to effect the normalization of the input XML stream (assuming that the XSLT instructions are contained in a file normalize.xsl):
operation XNORMALIZE params string I_INPUT : IN string I_ARGUMENTS : IN string I_NORMALIZED : OUT numeric I_STATUS : OUT string I_STATUSCONTEXT : OUT endparams activate "USYSXSLT".XMLTRANSFORM (I_INPUT, ".\normalize.xsl", I_ARGUMENTS, I_NORMALIZED, I_STATUS, I_STATUSCONTEXT) ; Handle activation errors HERE, by evaluating $status and $procerror. ; Handle errors that occured during validation HERE, by ; evaluating the expressions of I_STATUS and I_STATUSCONTEXT. end ; operation XNORMALIZE
Note: The XSLT instructions in this example are
generic; this means the stylesheet can be applied to any XML stream containing non-unique child
element names, or data in attribute values. However, mixed content (where an element contains a
mixture of text data and child elements) is not handled by this transformation. To use this
stylesheet on an XML stream containing mixed content, add the elements with mixed content to the
match
attribute of template disableTemplates
. This excludes the
mixed content from the output XML stream.

Get values from an XML stream using XSLT
It is possible to use XSLT to get single values or groups of values from an XML stream. The following XSLT instructions can be used for this:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="text"/> <xsl:strip-space elements="*"/> <!-- Disable output of these nodes (recursive). --> <xsl:template match="*" name="outputNothing"> <xsl:apply-templates select="*"/> </xsl:template> <!-- Output the value of this node. --> <xsl:template match="TargetNode" name="outputValueOf"> <xsl:value-of select="TargetValue"/> </xsl:template> </xsl:stylesheet>
The <xsl:output>
element
specifies that the output format of the stylesheet is text, not XML. This means that XML entities
are replaced by their replacement texts, so &
is output as
&
. The <xsl:strip-space>
element controls which
whitespace nodes are removed from the XML stream. This example removes all whitespace nodes.
Template outputNothing
recursively steps through all the elements in the XML stream, and assigns nothing to output. This
template produces empty output.
Template outputValueOf
matches a
specific element or set of elements specified by TargetNode, and outputs related
values specified in TargetValue. The match attribute of
outputValueOf
is more exact than that of outputNothing
, so the
XSLT processor applies outputValueOf
template preferentially.
The following XML stream is processed using this stylesheet:
<?xml version="1.0"?> <A> <A1>abc</A1> <A2>def</A2> <B> <B1>ghi</B1> <B2>jkl</B2> </B> <C> <C1>mno</C1> <C1>pqr</C1> <C1>stu</C1> </C> <C> <C1 att="goodbye ">vwx</C1> <C1 att="cruel ">yz1</C1> <C1 att="world">234</C1> </C> <C att="hello " att2="world"> <C1>567</C1> <C1>8</C1> <C1>9</C1> </C> <D><!-- comment. -->Mixed content <D1>element</D1> example.</D> </A>
TargetNode and TargetValue | Return value |
---|---|
TargetNode:
* TagetValue:
Return the value of all elements. Attribute values, comments, and processing instructions are not matched by TargetNode, and are therefore not returned. |
abcdefghijklmnopqrstuvwxyz
123456789Mixed content element example.
|
TargetNode:
C1 TargetValue:
Return the values of all
|
mnopqrstuvwxyz123456789
|
TargetNode:
C1[1] TargetValue:
Return the value of the first
|
mnovwx567
|
TargetNode:
C[2]/C1[3] TargetValue:
Return the value of the third
|
234
|
TargetNode: D |
D1 TargetValue:
Return the value of mixed content element
|
Mixed content element
example.
|
TargetNode:
C1 TargetValue:
Return the values of the
|
goodbye cruel world
|
TargetNode:
C[3] TargetValue:
Output the value of the first attribute
of the third |
hello
|
TargetNode:
D TargetValue:
Output the second text node of element
|
example.
|
TargetNode:
D TargetValue:
Output the first comment child of element
|
comment.
|
For an example of an operation wrapping this stylesheet, see operation GETXMLITEM.

Operation GETXMLITEM
This operation calls an XSLT stylesheet and returns the value of a node in an XML stream. The parameters can specify one node or several nodes.
GETXMLITEM
uses
$replace
to insert parameters
XNODE
and
XVALUE
into an XSLT stylesheet, and uses component
USYSXSLT to process the XSLT stylesheet. For
more information about the XSLT stylesheet used by this operation, and examples
of input and output data, see
USYSXSLT.
operation GETXMLITEM ; Get an item or set of items from an XML stream ; using XPATH patterns. ; Modify an XSLT stylesheet using the $replace ; function, and then activate USYSXSLT. params numeric I_STATUS : OUT string I_STATUSCONTEXT : OUT string I_XML : IN string XNODE : IN string XVALUE : IN string I_VALUE : OUT endparams variables string XSLTFILE endvariables fileload "getitem.xsl", XSLTFILE XSLTFILE = $replace(XSLTFILE, 1, "TargetNode", XNODE) XSLTFILE = $replace(XSLTFILE, 1, "TargetValue", XVALUE) filedump XSLTFILE, "getitemtemp.xsl" activate "USYSXSLT".XMLTRANSFORM(I_XML, "getitemtemp.xsl", " ", I_VALUE, I_STATUS, I_STATUSCONTEXT) end ; operation GETXMLITEM
Validation
It is often necessary to validate an XML stream before or after transformation.

Validate an XML stream
You can use the ProcScript statement
xmlvalidate
to validate an XML stream, even if the DTD for the XML
stream is not in your Repository.
The following operation
XVALIDATE
validates an XML stream using
xmlvalidate
:
operation XVALIDATE params numeric I_STATUS : OUT string I_STATUSCONTEXT : OUT string I_DTD : IN string I_XML : IN endparams ; I_DTD is a file path; use the argument /file ; to indicate this to xmlvalidate. xmlvalidate/file I_XML, I_DTD I_STATUS = $procerror I_STATUSCONTEXT = $procerrorcontext end ; operation XVALIDATE