XML XSLT

This page documents how to store your data in a valid XML file so you can convert it in all the formats you need with the help of XSLT. The examples are for a small adress-list containing a name, the sex and a list of phonenumbers.

The Grammar

In order to define what structure our XML file should have, we need to define that.

XML Grammar via DTD

You can define the structure of an XML file via a Document Type Definition (DTD) file.


<!ELEMENT mylist (Person*)>
<!ELEMENT Person (Name, Geschlecht?, Telefon*)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Telefon (#PCDATA)>
<!ATTLIST Telefon
type CDATA #IMPLIED
>

Now we have an address-list for any number of persons (even putting nobody in there is allowed). One person consists of a Name, a sex (optional) and so much phone-numbers you like (even none). A phone-number can have a parameter called type. See also

XML Grammar via XSD

Defining the structure of an XML file via an XML Schema (XSD) file (which is an XML file, too) offers even more possibilities.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

 <xsd:element name="mylist" type="MyContactsType" />

 <xsd:complexType name="MyContactsType">
   <xsd:sequence>
    <xsd:element name="Person" type="PersonType" maxOccurs="unbounded" />
   </xsd:sequence>
 </xsd:complexType>

 <xsd:complexType name="PersonType">
     <xsd:element name="Name"       type="xsd:string"  maxOccurs="1"  minOccurs="1"/>
     <xsd:element name="Geschlecht"                    maxOccurs="1"  minOccurs="1">
                <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                                <xsd:enumeration value="F"></xsd:enumeration>
                                <xsd:enumeration value="M"></xsd:enumeration>
                                <xsd:enumeration value="?"></xsd:enumeration>
                        </xsd:restriction>
                </xsd:simpleType>
     </xsd:element>
     <xsd:element name="Telefon"    type="TelefonType" maxOccurs="unbounded" />
 </xsd:complexType>

 <xsd:complexType name="TelefonType">
        <xsd:attribute name="type">
                <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                                <xsd:enumeration value="Mobile"></xsd:enumeration>
                                <xsd:enumeration value="Private"></xsd:enumeration>
                        </xsd:restriction>
                </xsd:simpleType>
        </xsd:attribute>
 </xsd:complexType>

</xsd:schema>

Write your XML file

Now it's time to write your data in an xml file. Remember to respect the Grammar you just defined.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mylist SYSTEM "mylist.dtd">

 <mylist>

  <Person>
   <Name>John Doe</Name>
   <Geschlecht>M</Geschlecht>
   <Telefon type="Mobil">555 123</Telefon>
   <Telefon>555 647</Telefon>
  </Person>

  <Person>
   <Name>Jane Doe</Name>
   <Geschlecht>F</Geschlecht>
  </Person>

 </mylist>

See also:

Write a xsl file

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text" /><xsl:template match="/">

 <xsl:template match="/">

  <xsl:for-each select="tgadressbuch/Person">
   <xsl:sort select="Nachname"/>
   <xsl:sort select="Vorname"/>

   <xsl:apply-templates select="Nachname"/>
   <xsl:apply-templates select="Vorname"/>
   <xsl:apply-templates select="Telefonnummer"/>

  </xsl:for-each>

 </xsl:template>
</xsl:stylesheet>
 

This would go through the whole xml file and would output everything. But you don't need for-each for that:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text" /><xsl:template match="/">

 <xsl:template match="/">
  <xsl:apply-templates select="Person">
   <xsl:sort select="Nachname"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="Person">
  <xsl:apply-templates select="Nachname"/>
  <xsl:apply-templates select="Vorname"/>
  <xsl:apply-templates select="Telefonnummer"/>
 </xsl:template>

</xsl:stylesheet>
 

You can even have conditional parts:

<xsl:choose>
 <xsl:when test="Geschlecht='M'">
   Frau!
 </xsl:when>
 <xsl:when test="Geschlecht='F'">
   Mann!
 </xsl:when>
 <xsl:otherwise>
   Keine Person.
 </xsl:otherwise>
</xsl:choose>
 

Explain what elements you want to deal with:

<xsl:apply-templates select="Telefon[not(Telefon='555 123')]"
<xsl:apply-templates select="Telefon[Telefon[(@type='Mobil')]">

Assemble an element with an attribute.

<xsl:element name = "a" >
  <xsl:attribute name = "href">
   http://www.example.com
   <xsl:apply-templates />
  </xsl:attribute>
  Ein Link
</xsl:element>

Change the characteristics of the output document

<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:output method="text" />

See also

Use your xml and your xslt file to create a new file

e.g. with xsltproc:

xsltproc -o output.txt my_xslt.xsl data.xml

Validate an xml file against an xml schema

xmllint --noout --schema myschema.xsd myfile.xml

Examples

Rename an element

Assume you have the following

<foo a="5"> ...
</foo>

and want to rename it to

<bar a="5">
 ...
</bar>

Solution

<xsl:template match="foo"> <xsl:element name="bar">
  <xsl:copy-of select="@*"/>
  <xsl:apply-templates/>
 </xsl:element>
</xsl:template>

is to write bar if you read foo. The trick is to use copy-of to keep the attributes.

Construct your own function

You can construct your own functions and even pass parameters to it. However, these parameters are nodesets an no normal string like parameters. So you can not add strings to such a parameter (at least not until now and not without further software modules).

<xsl:variable name="var1" select="//FOO/BAR/text()"    />
<xsl:variable name="var2">//AAA/CCC/text()</xsl:variable>

<xsl:template match="/">
  <xsl:call-template name="function">
   <xsl:with-param name="var3" select="//FOO/BAR/"      />
   <xsl:with-param name="var4">//FOO/BAR/</xsl:with-param>
  </xsl:call-template>
</xsl:template>

<xsl:template name="function">
  <xsl:param name="var3"/>
  <xsl:param name="var4"/>

  <xsl:value-of select="$var1"/>
  <xsl:value-of select="$var2"/>
  <xsl:value-of select="$var3"/>
  <xsl:value-of select="$var4"/>

</xsl:template>

Modes

<xsl:template  match="/foo">
  <xsl:apply-templates  select="bar" mode="m1"/>
  <xsl:apply-templates  select="bar" mode="m2"/>
  <xsl:apply-templates  select="bar" mode="m3"/>
</xsl:template>

<xsl:template  match="bar" mode="m1">
 ...
</xsl:template>

<xsl:template  match="bar" mode="m2">
 ...
</xsl:template>

<xsl:template  match="bar" mode="m3">
 ...
</xsl:template>

Match examples

<xsl:template match="foo|bar|blub"   >
<xsl:template match="foo[@bar='bar']">
<xsl:template match="foo[bar]"       >