开发者

How can I use annotations in XSD to map XML integers to the related descriptions?

开发者 https://www.devze.com 2023-01-05 13:30 出处:网络
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. T

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开发者_StackOverflow社区 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.


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>


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消