Norbox
Norbox

Reputation: 31

Parse XSLT attribute as an array

I'm using XSLT to create HTML forms from XML. Forms are dynamically created. There is no ready teamplate for that. There will be as many inputs as user wants. I want to keep it as short as possible so I'm using attributes to create e.g. options in select tags. The problem is that I can't figure out how to turn this XML:

<input mapTo="dropdown" nameId="sampleId" inputDomain="[a, b, c, d, e]" />

into:

<select id="sampleId">
    <option value="a">a</option>
    <option value="b">b</option>
    <option value="c">c</option>
    <option value="d">d</option>
    <option value="e">e</option>
</select>

My problem is exactly the inputDomain attribute. I can modify for an easier method but I want to keep it in one attribute (like an array). Is it possible? Or maybe you have more convenient ideas?

Upvotes: 0

Views: 283

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167696

If you use schema-aware XSLT 2 or 3 (e.g. with Saxon 9 or 10 EE) you can declare the attribute as type xs:NMTOKENS and use a space separated list:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="input">
    <xs:complexType>
      <xs:attribute name="inputDomain" type="xs:NMTOKENS" use="required"/>
      <xs:attribute name="mapTo" use="required" type="xs:NCName"/>
      <xs:attribute name="nameId" use="required" type="xs:NCName"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Then a stylesheet processing

<input mapTo="dropdown" nameId="sampleId" inputDomain="a b c d e" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd"/>

can use the data function on the attribute to have a sequence of tokens:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    expand-text="yes"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:template match="input[@mapTo = 'dropdown']">
        <select id="{@nameId}">
            <xsl:for-each select="data(@inputDomain)">
                <option value="{.}">{.}</option>
            </xsl:for-each>
        </select>
    </xsl:template>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:output method="html" indent="yes" html-version="5"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Example</title>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117073

Consider the following example:

XML

<input mapTo="dropdown" nameId="sampleId" inputDomain="a,b,c,d,e" />

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="input">
    <select id="sampleId">
        <xsl:for-each select="tokenize(@inputDomain, ',')">
            <option value="{.}">
                <xsl:value-of select="." />
            </option>
        </xsl:for-each>
    </select>
</xsl:template>

</xsl:stylesheet>

Result

<?xml version="1.0" encoding="UTF-8"?>
<select id="sampleId">
   <option value="a">a</option>
   <option value="b">b</option>
   <option value="c">c</option>
   <option value="d">d</option>
   <option value="e">e</option>
</select>

Demo: http://xsltfiddle.liberty-development.net/3MvmXiL

Upvotes: 1

Related Questions