Thursday 31 October 2013

XSD schema: Sequence of Optional Elements where one Element is allowed in any Position

A requirement recently arose where I needed to have a sequence of optional elements foo1, foo2, foo3, foo4, f005 where an optional element bar was permitted between any one of the foo{n} elements.

The following definition demonstrates a definition for just such a case, where foo2 can have multiple occurrences.

<xsd:element name="container">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:choice minOccurs="0" >
        <xsd:sequence>
          <xsd:element ref="foo1"/>
          <xsd:element ref="bar"  minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence> 
      </xsd:choice>
      <xsd:choice minOccurs="0"  maxOccurs="unbounded">
        <xsd:sequence>
          <xsd:element ref="foo2"/>
          <xsd:element ref="bar"  minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence> 
      </xsd:choice>
      <xsd:choice minOccurs="0" >
        <xsd:sequence>
          <xsd:element ref="foo3"/>
          <xsd:element ref="bar"  minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence> 
      </xsd:choice>
      <xsd:choice minOccurs="0" >
        <xsd:sequence>
          <xsd:element ref="foo4"/>
          <xsd:element ref="bar"  minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence> 
      </xsd:choice>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element> 

Wednesday 30 October 2013

XSLT - return filename of the input document

On occasion one needs to use the input filename of the document that is being transformed. This can be supplied as a parameter, but it can also be determined within the XSLT by using either the base-uri() or document-uri() functions. Use global variables to return the uri of the document and then using the forward slash to tokenize the variable. The last token will be the filename.



<xsl:variable name="base-uri" select="base-uri(.)"/>
<xsl:variable name="document-uri" select="document-uri(.)"/>
 
<xsl:variable name="filename" select="(tokenize($document-uri,'/'))[last()]"/>
 
<xsl:template match="/">
 <docs>
  <uri><xsl:value-of select="$document-uri"/></uri>
  <uri><xsl:value-of select="$base-uri"/></uri>
  <filename><xsl:value-of select="$filename"/></filename>
  <xsl:apply-templates/>
 </docs>
</xsl:template> 

Thursday 24 October 2013

XSLT: Quotation marks and apostrophes

XSLT 1 - Single quotes and apostrophes

An intriguing issue came up when trying to remove an apostrophe from a text string using XSLT 1. After a little research I found this method of getting around it:

It was a simple case of transposing the double quotes and single quotes in the element and function

<xsl:value-of select='translate($textstring, "&apos;", "_")'/>

This worked for both Saxon6 and MS transformation engines

XSLT 1 - Double quotes

For double quotes use:

<xsl:value-of select="translate(regex-group(2),'&quot;', '')"/>

XSLT 2 - Single quotes and apostrophes

When using XSLT 2 the same result can be achieved using:

<xsl:value-of select="translate($textstring, '''', '_')"/>

or:

<xsl:value-of select="replace($textstring, '''', '_')"/>

XSLT 2 - Double quotes

A similar mechanism can be used with XSLT for double quotes, either:

<xsl:value-of select='translate($textstring, """", "_")'/>

or:

<xsl:value-of select='replace($textstring, """", "_")'/>

Monday 21 October 2013

Namespace Identity Transformation

A simple identity transformation for switching namespaces

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="oldNS" select="'http://foo/1.0'"/>
 <xsl:param name="newNS" select="'http://bar/1.0'"/>

 <xsl:template match="/">
  <xsl:apply-templates/>
 </xsl:template> 
 
 <xsl:template match="*">
  <xsl:element name="{name()}" namespace="{$newNS}">
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:choose>
   <xsl:when test="namespace-uri()=$oldNS">
    <xsl:attribute name="{name()}" namespace="{$newNS}">
     <xsl:value-of select="."/>
    </xsl:attribute>
   </xsl:when>
   <xsl:otherwise>
    <xsl:copy-of select="."/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

</xsl:stylesheet>