tags:

views:

33

answers:

2

I am writing an XSLT for turning an XML file into a human-readable HTML page.

The XML has several fields to describe some aspects of the data, which contain integers which represent mapped strings. The integers are not the information the user wants, I need to map those integers to the corresponding strings.

The mapped strings are available in annotations in the XSD.

For example:

<typewoning>1</typewoning>

Following the XSD declaration:

<xs:element name="typewoning" type="TypeWoningEnum"/>

Maps to:

    <xs:simpleType name="TypeWoningEnum">
    <xs:restriction base="xs:integer">
        <xs:enumeration value="1">
            <xs:annotation>
                <xs:documentation>vrijstaande woning</xs:documentation>
            </xs:annotation>
        </xs:enumeration>
        <xs:enumeration value="2">
            <xs:annotation>
                <xs:documentation>twee-onder-een-kap/rijwoning hoek</xs:documentation>
            </xs:annotation>
        </xs:enumeration>

etc etc

So in this case, I want to display the annotation for value 1, which should be 'vrijstaande woning'.

What's the best way of approaching this? I'm not that experienced yet in XML/XSLT to know of any of those solutions, and my google searches have turned up nothing useable.

Thanks in advance.

+1  A: 

If I read this correctly, then what you're trying to do is not straight-forward. There is no "magic" connection between the XML document and the schema, you will have to load the schema in the stylesheet and find the documentation in it.

Assuming that at a certain point your XSLT stylesheet is in a position where typewoning is under the context element (i.e. value-of select="typewoning" would output its value), you can do this:

<xsl:variable name="schema" select="document('my-schema.xsd')/xsd:schema"/>

<xsl:variable name="type" select="$schema//xsd:simpleType[@name = 'TypeWoningEnum']"/>

<xsl:variable name="value" select="$type//xsd:enumeration[@value = typewoning]//xsd:documentation"/>

<xsl:value-of select="$value"/>

Some explanation:

  1. The first step loads the schema into a variable using the XSL document function
  2. The second step finds the right type (you could probably get fancier and find the type using the element's type in the document, but then schema validation would have to be on and you need a schema-compliant XSLT engine)
  3. The third step finds the documentation value to output, given the content of your typewoning element.

Fourth step writes the result out, use as you wish.

Edit: an alternative, if you are willing to use a schema-compliant XSLT engine, such as the paid for version of saxon. Assuming all your enumerations derive from integer, you can try this within the context of some parent node:

<xsl:variable name="schema" select="document('my-schema.xsd')/xsd:schema"/>

<xsl:for-each select="element(*, xsd:integer)">
    <xsl:variable name="type" select="$schema//xsd:simpleType[@name = local-name(current())]"/>

    <xsl:if test="$type">
        <xsl:variable name="value" select="$type//xsd:enumeration[@value = current()/text()]//xsd:documentation"/>

        <xsl:text>Value: </xsl:text> <xsl:value-of select="$value"/>
    </xsl:if>
</xsl:for-each>
xcut
Thank you kindly for elaborating. I was hoping that there might be some magic mapping tool, which would map integers as part of an enumerated type to the annotations in the XSD.I have about 20 to 30 fields where I have to perform this mapping, so your solution, although good and correct, would somewhat pollute my 'to-HTML' xsl stylesheet.I think I may use your code to first perform the mapping on the xml source, and output a 'mapped' xml source, which I would then translate to html.I am even contemplating writing an XSL to transform the XSD into an XSL which will do the mapping... Crazy.
Symen Timmermans
@Symen Timmermans: It seems that you have cross references here. This could be done in a general way without "pollute" your stylesheet. It requires the use of `xsl:key`. If you provide a reduce but full example of your two input document (data and schema) and desired output, someone could post an answer.
Alejandro
@Symon Timmermans: added a further example showing how this can be simplified if you are willing to use a schema-aware XSLT processor.
xcut
A: 

I have put some time and energy into this, I decided to write an XSLT to transform the schema to a mapping based on the enumeration documentation found in every xs:simpleType.

This code:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0">

<xsl:output method="xml" version="1.0"
    encoding="utf-8" indent="yes"/>

<xsl:strip-space elements="*"/>

<xsl:template match="xs:schema">
    <mappings>
        <xsl:for-each select="//xs:element[contains(@type, 'Enum')] | //xs:element[contains(@type, 'JaNee')]">
            <xsl:variable name="type" select="@type" />
            <xsl:element name="{concat(@name, 'Mapping')}" >
                <xsl:apply-templates select="//xs:simpleType[@name=$type]">
                    <xsl:with-param name="elemname" select="@name" />
                </xsl:apply-templates>
            </xsl:element>
        </xsl:for-each>
    </mappings>
</xsl:template>

<xsl:template match="xs:enumeration">
    <xsl:param name="elemname" select="'undefined'" />
    <xsl:element name="{$elemname}">
        <xsl:attribute name="value">
            <xsl:value-of select="@value" />
        </xsl:attribute>
        <xsl:value-of select="xs:annotation/xs:documentation" />
    </xsl:element>
</xsl:template>

Outputs exactly what I was hoping for:

    ...snip...
   <typewoningMapping>
      <typewoning value="1">vrijstaande woning</typewoning>
      <typewoning value="2">twee-onder-een-kap/rijwoning hoek</typewoning>
      <typewoning value="3">rijwoning tussen</typewoning>
      <typewoning value="4">galerijflat (hoogbouw)</typewoning>
      <typewoning value="5">portiekflat (etage)</typewoning>
      <typewoning value="6">maisonnettewoning</typewoning>
      <typewoning value="7">flatwoning (overig)</typewoning>
      <typewoning value="8">woongebouw met niet-zelfstandige woonruimte</typewoning>
   </typewoningMapping>
   ...snip...

Now I only have to write something that makes an xsl with the xsl:key tags defined for the mappings I want to use.

Thanks to all for helping me along the way.

Symen Timmermans