开发者

Simple XSLT template

There is XML document:

<data>how;many;i;can;tell;you</data>

Need to get XML using XSLT version 1:

 <manydata>
     <onedata>how</onedata>
     <onedata>many</onedata>
     <onedata>i</onedata>
     <onedata>can</onedata>
     <onedata>tell</onedata>
     <onedata>you</onedata>
   </manydata>

How I can do it?

UPDATE: Output format must 开发者_如何学JAVAbe XML.


This recursive solution is probably one of the shortest possible:

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

 <xsl:template match="data">
  <manydata><xsl:apply-templates/></manydata>
 </xsl:template>

 <xsl:template match="text()" name="tokenize">
  <xsl:param name="pText" select="."/>
   <xsl:if test="string-length($pText)">
      <onedata>
       <xsl:value-of select=
        "substring-before(concat($pText,';'),';')"/>
      </onedata>
      <xsl:call-template name="tokenize">
       <xsl:with-param name="pText" select=
        "substring-after($pText,';')"/>
      </xsl:call-template>
     </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document;

<data>how;many;i;can;tell;you</data>

the wanted, correct result is produced:

<manydata>
   <onedata>how</onedata>
   <onedata>many</onedata>
   <onedata>i</onedata>
   <onedata>can</onedata>
   <onedata>tell</onedata>
   <onedata>you</onedata>
</manydata>


<xsl:template match="data">
    <manydata>
        <!-- 
            empty <manydata/> will be generated,
            if <data/> without child text() 
        -->
        <xsl:apply-templates select="text()"/>
    </manydata>
</xsl:template>

<xsl:template match="data/text()">
    <!-- start point for recursion -->
    <xsl:call-template name="tokenize-string">
        <xsl:with-param name="separator" select="';'"/>
        <xsl:with-param name="string" select="text()"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="tokenize-string">
    <xsl:param name="separator"/>
    <xsl:param name="string"/>
    <xsl:variable name="string-before-separator" 
        select="substring-before( $string, $separator )"/>
    <onedata>
        <xsl:choose>
            <!-- if $separator presents in $string take first piece -->
            <xsl:when test="$string-before-separator">
                <xsl:value-of select="$string-before-separator"/>
            </xsl:when>
            <!-- take whole $string, if no $separator in the $string -->
            <xsl:otherwise>
                <xsl:value-of select="$string"/>
            </xsl:otherwise>
        </xsl:choose>
    </onedata>
    <!-- recursive call, if separator was found -->
    <xsl:if test="$string-before-separator">
        <xsl:call-template name="tokenize-string">
            <xsl:with-param name="separator" select="$separator"/>
            <xsl:with-param name="string" 
                select="substring-after( $string, $separator )"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>


Try this:

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

  <xsl:template match="data">
   <xsl:element name="manydata">
      <xsl:call-template name="splitsemicolons">
        <xsl:with-param name="text" select="text()" />
      </xsl:call-template>
    </xsl:element>
  </xsl:template>

  <xsl:template name="splitsemicolons">
    <xsl:param name="text" />
    <xsl:choose>
      <xsl:when test="contains($text,';')">
        <xsl:element name="onedata">
          <xsl:value-of select="substring-before($text,';')" />
         </xsl:element>
         <xsl:call-template name="splitsemicolons">
           <xsl:with-param name="text" select="substring-after($text,';')" />
         </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
         <xsl:element name="onedata">
           <xsl:value-of select="$text" />
         </xsl:element>
       </xsl:otherwise>
     </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

This uses a named template that is called recursively, each time outputting what's before the first ;, and calling itself with everything after the first ;. If there isn't a ;, it just outputs whatever's left as-is.


You can use the XSLT extension library to get the tokenize function. Here is how the final code will look like:

<xsl:template match="/">
 <manydata>
 <xsl:for-each select="str:tokenize(data, ';')">
      <xsl:value-of select="." />
   </xsl:for-each> 
 </manydata>
</xsl:template>
</xsl:stylesheet>

Please note you will have to import the extension library into you XSLT using:

<xsl:import href="path/str.xsl" />

before you use the library functions.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜