XSLT 2.0 question: wrapping in an arbitrary number of elements

S

Stryder

Hi. I'm writing XSLT 2.0 templates and am trying to do the following
without writing extension functions. I'm trying to go from this...

<outer>
<wrapin>one two three</wrapin>
<wrapme>some text</wrapme>
</outer>

to this...

<outer>
<one>
<two>
<three>some text</three>
</two>
</one>
</outer>

wrapping the text in <wrapme> in an arbitrary number of elements based
on and named after the text nodes under <wrapin>. I can't figure out
a way to do this. I'm getting fairly well versed in XSLT 2.0,
including using regular expressions and the new grouping elements/
functions but I haven't figured out a way to do this. Any help would
be appreciated.

Thanks.
 
M

Martin Honnen

Stryder said:
Hi. I'm writing XSLT 2.0 templates and am trying to do the following
without writing extension functions. I'm trying to go from this...

<outer>
<wrapin>one two three</wrapin>
<wrapme>some text</wrapme>
</outer>

to this...

<outer>
<one>
<two>
<three>some text</three>
</two>
</one>
</outer>

wrapping the text in <wrapme> in an arbitrary number of elements based
on and named after the text nodes under <wrapin>. I can't figure out
a way to do this. I'm getting fairly well versed in XSLT 2.0,
including using regular expressions and the new grouping elements/
functions but I haven't figured out a way to do this. Any help would
be appreciated.

Here is a solution using a recursive function:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:mh="http://example.com/2009/mh"
exclude-result-prefixes="mh xsd"
version="2.0">

<xsl:eek:utput method="xml" indent="yes"/>

<xsl:template match="outer">
<xsl:copy>
<xsl:apply-templates select="wrapin"/>
</xsl:copy>
</xsl:template>

<xsl:function name="mh:wrap" as="element()*">
<xsl:param name="el-names" as="xsd:string*"/>
<xsl:param name="text" as="xsd:string"/>
<xsl:if test="exists($el-names[1])">
<xsl:element name="{$el-names[1]}">
<xsl:choose>
<xsl:when test="not(exists($el-names[2]))">
<xsl:value-of select="$text"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:sequence select="mh:wrap($el-names[position() gt 1],
$text)"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:element>
</xsl:if>
</xsl:function>

<xsl:template match="wrapin">
<xsl:sequence select="mh:wrap(tokenize(., '\s+'),
data(following-sibling::wrapme[1]))"/>
</xsl:template>

</xsl:stylesheet>
 
S

Stryder

Stryder said:
Hi.  I'm writing XSLT 2.0 templates and am trying to do the following
without writing extension functions.  I'm trying to go from this...
<outer>
    <wrapin>one two three</wrapin>
    <wrapme>some text</wrapme>
</outer>
to this...
<outer>
    <one>
        <two>
            <three>some text</three>
        </two>
    </one>
</outer>
wrapping the text in <wrapme> in an arbitrary number of elements based
on and named after the text nodes under <wrapin>.  I can't figure out
a way to do this.  I'm getting fairly well versed in XSLT 2.0,
including using regular expressions and the new grouping elements/
functions but I haven't figured out a way to do this.  Any help would
be appreciated.

Here is a solution using a recursive function:

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:mh="http://example.com/2009/mh"
   exclude-result-prefixes="mh xsd"
   version="2.0">

   <xsl:eek:utput method="xml" indent="yes"/>

   <xsl:template match="outer">
     <xsl:copy>
       <xsl:apply-templates select="wrapin"/>
     </xsl:copy>
   </xsl:template>

   <xsl:function name="mh:wrap" as="element()*">
     <xsl:param name="el-names" as="xsd:string*"/>
     <xsl:param name="text" as="xsd:string"/>
     <xsl:if test="exists($el-names[1])">
         <xsl:element name="{$el-names[1]}">
           <xsl:choose>
             <xsl:when test="not(exists($el-names[2]))">
               <xsl:value-of select="$text"/>
             </xsl:when>
             <xsl:eek:therwise>
               <xsl:sequence select="mh:wrap($el-names[position() gt 1],
$text)"/>
             </xsl:eek:therwise>
           </xsl:choose>
         </xsl:element>
     </xsl:if>
   </xsl:function>

   <xsl:template match="wrapin">
     <xsl:sequence select="mh:wrap(tokenize(., '\s+'),
data(following-sibling::wrapme[1]))"/>
   </xsl:template>

</xsl:stylesheet>

Thanks that's just what I needed.
 
S

Stryder

Stryder said:
Hi.  I'm writing XSLT 2.0 templates and am trying to do the following
without writing extension functions.  I'm trying to go from this...
<outer>
    <wrapin>one two three</wrapin>
    <wrapme>some text</wrapme>
</outer>
to this...
<outer>
    <one>
        <two>
            <three>some text</three>
        </two>
    </one>
</outer>
wrapping the text in <wrapme> in an arbitrary number of elements based
on and named after the text nodes under <wrapin>.  I can't figure out
a way to do this.  I'm getting fairly well versed in XSLT 2.0,
including using regular expressions and the new grouping elements/
functions but I haven't figured out a way to do this.  Any help would
be appreciated.

Here is a solution using a recursive function:

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:mh="http://example.com/2009/mh"
   exclude-result-prefixes="mh xsd"
   version="2.0">

   <xsl:eek:utput method="xml" indent="yes"/>

   <xsl:template match="outer">
     <xsl:copy>
       <xsl:apply-templates select="wrapin"/>
     </xsl:copy>
   </xsl:template>

   <xsl:function name="mh:wrap" as="element()*">
     <xsl:param name="el-names" as="xsd:string*"/>
     <xsl:param name="text" as="xsd:string"/>
     <xsl:if test="exists($el-names[1])">
         <xsl:element name="{$el-names[1]}">
           <xsl:choose>
             <xsl:when test="not(exists($el-names[2]))">
               <xsl:value-of select="$text"/>
             </xsl:when>
             <xsl:eek:therwise>
               <xsl:sequence select="mh:wrap($el-names[position() gt 1],
$text)"/>
             </xsl:eek:therwise>
           </xsl:choose>
         </xsl:element>
     </xsl:if>
   </xsl:function>

   <xsl:template match="wrapin">
     <xsl:sequence select="mh:wrap(tokenize(., '\s+'),
data(following-sibling::wrapme[1]))"/>
   </xsl:template>

</xsl:stylesheet>

Here's another one...

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:eek:utput method="xml" indent="yes"/>

<xsl:template match="/">
<xsl:variable name="names" select="('one', 'two', 'three')"/>
<xsl:call-template name="wrapem">
<xsl:with-param name="names_param" select="('one', 'two',
'three')"/>
<xsl:with-param name="text_param"><xsl:text>some text to
put in the element</xsl:text></xsl:with-param>
</xsl:call-template>
</xsl:template>

<xsl:template name="wrapem">
<xsl:param name="names_param"/>
<xsl:param name="text_param"/>
<xsl:for-each select="$names_param[position()=1]">
<xsl:variable name="element_name" select="."/>
<xsl:element name="{$element_name}">
<xsl:if test="count($names_param) = 1">
<xsl:value-of select="text_param"/>
</xsl:if>
<xsl:call-template name="wrapem"><xsl:with-param
name="names_param" select="$names_param[position() != 1]"/></xsl:call-
template>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top