XSLT & String manipulation query

Discussion in 'XML' started by Bilal, Oct 6, 2006.

  1. Bilal

    Bilal Guest

    Hello,
    I'm trying to perform some string manipulations in my stylesheet and
    have gotten stuck on the issue below so hopefully can elicit some useful
    hints.

    Namely, the problem is that I need to convert an unqualified Xpath to
    a fully qualified Xpath in an identity transform, i.e.

    /AAA/BBB/CCC/@DDD

    converted to

    /ns:AAA/ns:BBB/ns:CCC/@DDD

    with a predefined NS prefix and using a string tokenizer (adopted from
    http://www.xslt.com/html/xsl-list/2005-04/msg00031.html) which returns
    the tokens as:

    <token>AAA</token>
    <token>BBB</token>
    <token>CCC</token>
    <token>@DDD</token>

    I'm assigning to the variable 'tokens' in the following template, which
    then tries to produce the fully qualified namespace:

    <xsl:template name="qualifiedXpath">
    <xsl:param name="unqualifiedXpath"/>
    <!-- -->
    <xsl:variable name="sampleUnqualifiedXpath"
    select="'/AAA/BBB/CCC/@DDD'"/>
    <!-- hardcoded namespace prefix -->
    <xsl:variable name="prefixString" select="'dns:'"/>
    <!-- hardcoded delimiter character -->
    <xsl:variable name="slash" select="'/'"/>
    <!-- Variable to contain the tokens -->
    <xsl:variable name="tokens">
    <!-- Calling tokenizer template-->
    <xsl:call-template name="tokenizer">
    <xsl:with-param name="string" select="$sampleUnqualifiedXpath"/>
    <xsl:with-param name="delimiter" select="$slash"/>
    </xsl:call-template>
    </xsl:variable>
    <!-- Variable to hold the qualified Xpath -->
    <xsl:variable name="qualXpath">
    <!-- Constructing the qualified Xpath-->
    <!-- Iterate through the returned token nodes -->
    <xsl:for-each select="$tokens/token">
    <!-- Add delimiter-->
    <xsl:value-of select="$slash"/>
    <!-- Add prefix only when token is an element name i.e. doesn't have the
    @ character -->
    <xsl:if test="not(contains(.,'@'))">
    <!-- Adding namespace prefix -->
    <xsl:value-of select="$prefixString"/>
    <!-- Add token's value -->
    <xsl:value-of select="."/>
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>
    <!-- returning qualXpath variable -->
    <xsl:value-of select="$qualXpath"/>
    </xsl:template>

    where the tokens' usage in the loop declaration
    <xsl:for-each select="$tokens/token">

    is causing a Result Tree Fragment (RTF) error; I've googled to find out
    more about it but frankly don't understand the problem, and unsure what
    an alternative solution would be and hence seeking Wisdom of The Elders!
    :)

    BTW, the code snippet above might be buggy (hopefully not too much) as
    I've been stuck at this RTF error and hence unable to proceed. I suspect
    the usage of contains(.,'@'),
    where I intend to check the token node's value for a '@' character, is
    bit fishy. :)

    Many thanks!

    Regards,

    Bilal B.





    *** Sent via Developersdex http://www.developersdex.com ***
     
    Bilal, Oct 6, 2006
    #1
    1. Advertising

  2. In article <45264108$0$25785$>,
    Bilal <> wrote:

    ><xsl:variable name="tokens">
    ><!-- Calling tokenizer template-->
    ><xsl:call-template name="tokenizer">
    ><xsl:with-param name="string" select="$sampleUnqualifiedXpath"/>
    ><xsl:with-param name="delimiter" select="$slash"/>
    ></xsl:call-template>
    ></xsl:variable>


    Here you construct a result-tree fragment - the value of the variable
    "tokens" is not a nodeset from the original document, but a
    constructed nodeset.

    In XSLT 1.0 you can't do much with result-tree fragments. In particular
    you can't do this sort of thing:

    ><xsl:for-each select="$tokens/token">


    Many XSLT processors have an extension function that allows you to convert
    a result-tree fragment into an ordinary nodeset. For example, the
    exsl:node-set() function may be available, see

    http://www.exslt.org/exsl/functions/node-set/

    -- Richard
     
    Richard Tobin, Oct 6, 2006
    #2
    1. Advertising

  3. As Richard implied, XSLT 2.0 (when it becomes official and more widely
    available) removes that distinction between nodesets and result-tree
    fragments.

    If you don't want to rely on the extension function, the other 1.0
    solution is to rewrite the tokenize-and-reconstruct process so it yields
    the new string directly, rather than producing an RTF and then walking
    that to produce the string. There are examples of recursive substring
    replacement on the XSLT FAQ website, among many other places; it's a
    fairly common idiom for functional languages like XSLT.

    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Joe Kesselman, Oct 6, 2006
    #3
  4. Bilal

    Bilal Guest

    Hi Richard & Joe,
    Thanks for the explanation and suggestions. Joe, based on your
    suggestion, I started exploring other solution and I think I've come
    across a search-and-replace method in my XSLT cookbook which does this
    job. Now time to understand and customize it! ;-)

    BTW, I'm sure I'm not the only one with procedural language experience
    who has trouble with this functional language; its seems like a whole
    different beast!

    Many thanks for the help guys!

    Regards,

    Bilal B.



    *** Sent via Developersdex http://www.developersdex.com ***
     
    Bilal, Oct 6, 2006
    #4
  5. This transformation:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:testmap="testmap"
    exclude-result-prefixes="xsl testmap"
    >

    <xsl:import href="str-map.xsl"/>

    <!-- to be applied on any xml source -->

    <testmap:testmap/>

    <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="/">
    <xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/>
    <xsl:call-template name="str-map">
    <xsl:with-param name="pFun" select="$vTestMap"/>
    <xsl:with-param name="pStr"
    select="substring-before('/AAA/BBB/CCC/@DDD', '/@')"/>
    </xsl:call-template>
    <xsl:value-of select=
    "concat('/@', substring-after('/AAA/BBB/CCC/@DDD', '/@'))"/>
    </xsl:template>

    <xsl:template name="double" match="testmap:*">
    <xsl:param name="arg1"/>

    <xsl:value-of select="$arg1"/>
    <xsl:if test="$arg1 = '/'">
    <xsl:value-of select="'ns:'"/>
    </xsl:if>
    </xsl:template>

    </xsl:stylesheet>

    when applied on any source xml document (not used),

    produces the wanted result:

    /ns:AAA/ns:BBB/ns:CCC/@DDD


    Cheers,
    Dimitre Novatchev

    "Bilal" <> wrote in message
    news:45264108$0$25785$...
    > Hello,
    > I'm trying to perform some string manipulations in my stylesheet and
    > have gotten stuck on the issue below so hopefully can elicit some useful
    > hints.
    >
    > Namely, the problem is that I need to convert an unqualified Xpath to
    > a fully qualified Xpath in an identity transform, i.e.
    >
    > /AAA/BBB/CCC/@DDD
    >
    > converted to
    >
    > /ns:AAA/ns:BBB/ns:CCC/@DDD
    >
    > with a predefined NS prefix and using a string tokenizer (adopted from
    > http://www.xslt.com/html/xsl-list/2005-04/msg00031.html) which returns
    > the tokens as:
    >
    > <token>AAA</token>
    > <token>BBB</token>
    > <token>CCC</token>
    > <token>@DDD</token>
    >
    > I'm assigning to the variable 'tokens' in the following template, which
    > then tries to produce the fully qualified namespace:
    >
    > <xsl:template name="qualifiedXpath">
    > <xsl:param name="unqualifiedXpath"/>
    > <!-- -->
    > <xsl:variable name="sampleUnqualifiedXpath"
    > select="'/AAA/BBB/CCC/@DDD'"/>
    > <!-- hardcoded namespace prefix -->
    > <xsl:variable name="prefixString" select="'dns:'"/>
    > <!-- hardcoded delimiter character -->
    > <xsl:variable name="slash" select="'/'"/>
    > <!-- Variable to contain the tokens -->
    > <xsl:variable name="tokens">
    > <!-- Calling tokenizer template-->
    > <xsl:call-template name="tokenizer">
    > <xsl:with-param name="string" select="$sampleUnqualifiedXpath"/>
    > <xsl:with-param name="delimiter" select="$slash"/>
    > </xsl:call-template>
    > </xsl:variable>
    > <!-- Variable to hold the qualified Xpath -->
    > <xsl:variable name="qualXpath">
    > <!-- Constructing the qualified Xpath-->
    > <!-- Iterate through the returned token nodes -->
    > <xsl:for-each select="$tokens/token">
    > <!-- Add delimiter-->
    > <xsl:value-of select="$slash"/>
    > <!-- Add prefix only when token is an element name i.e. doesn't have the
    > @ character -->
    > <xsl:if test="not(contains(.,'@'))">
    > <!-- Adding namespace prefix -->
    > <xsl:value-of select="$prefixString"/>
    > <!-- Add token's value -->
    > <xsl:value-of select="."/>
    > </xsl:if>
    > </xsl:for-each>
    > </xsl:variable>
    > <!-- returning qualXpath variable -->
    > <xsl:value-of select="$qualXpath"/>
    > </xsl:template>
    >
    > where the tokens' usage in the loop declaration
    > <xsl:for-each select="$tokens/token">
    >
    > is causing a Result Tree Fragment (RTF) error; I've googled to find out
    > more about it but frankly don't understand the problem, and unsure what
    > an alternative solution would be and hence seeking Wisdom of The Elders!
    > :)
    >
    > BTW, the code snippet above might be buggy (hopefully not too much) as
    > I've been stuck at this RTF error and hence unable to proceed. I suspect
    > the usage of contains(.,'@'),
    > where I intend to check the token node's value for a '@' character, is
    > bit fishy. :)
    >
    > Many thanks!
    >
    > Regards,
    >
    > Bilal B.
    >
    >
    >
    >
    >
    > *** Sent via Developersdex http://www.developersdex.com ***
     
    Dimitre Novatchev, Oct 7, 2006
    #5
  6. Of course, the imported stylesheet is from the EXSLT-version of FXSL1.x

    When one has such a toolset, solving such problems takes just two minutes.

    Cheers,
    Dimitre Novatchev

    "Dimitre Novatchev" <> wrote in message
    news:452711e9$0$97218$...
    > This transformation:
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    > xmlns:testmap="testmap"
    > exclude-result-prefixes="xsl testmap"
    >>

    > <xsl:import href="str-map.xsl"/>
    >
    > <!-- to be applied on any xml source -->
    >
    > <testmap:testmap/>
    >
    > <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
    >
    > <xsl:template match="/">
    > <xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/>
    > <xsl:call-template name="str-map">
    > <xsl:with-param name="pFun" select="$vTestMap"/>
    > <xsl:with-param name="pStr"
    > select="substring-before('/AAA/BBB/CCC/@DDD', '/@')"/>
    > </xsl:call-template>
    > <xsl:value-of select=
    > "concat('/@', substring-after('/AAA/BBB/CCC/@DDD', '/@'))"/>
    > </xsl:template>
    >
    > <xsl:template name="double" match="testmap:*">
    > <xsl:param name="arg1"/>
    >
    > <xsl:value-of select="$arg1"/>
    > <xsl:if test="$arg1 = '/'">
    > <xsl:value-of select="'ns:'"/>
    > </xsl:if>
    > </xsl:template>
    >
    > </xsl:stylesheet>
    >
    > when applied on any source xml document (not used),
    >
    > produces the wanted result:
    >
    > /ns:AAA/ns:BBB/ns:CCC/@DDD
    >
    >
    > Cheers,
    > Dimitre Novatchev
    >
    > "Bilal" <> wrote in message
    > news:45264108$0$25785$...
    >> Hello,
    >> I'm trying to perform some string manipulations in my stylesheet and
    >> have gotten stuck on the issue below so hopefully can elicit some useful
    >> hints.
    >>
    >> Namely, the problem is that I need to convert an unqualified Xpath to
    >> a fully qualified Xpath in an identity transform, i.e.
    >>
    >> /AAA/BBB/CCC/@DDD
    >>
    >> converted to
    >>
    >> /ns:AAA/ns:BBB/ns:CCC/@DDD
    >>
    >> with a predefined NS prefix and using a string tokenizer (adopted from
    >> http://www.xslt.com/html/xsl-list/2005-04/msg00031.html) which returns
    >> the tokens as:
    >>
    >> <token>AAA</token>
    >> <token>BBB</token>
    >> <token>CCC</token>
    >> <token>@DDD</token>
    >>
    >> I'm assigning to the variable 'tokens' in the following template, which
    >> then tries to produce the fully qualified namespace:
    >>
    >> <xsl:template name="qualifiedXpath">
    >> <xsl:param name="unqualifiedXpath"/>
    >> <!-- -->
    >> <xsl:variable name="sampleUnqualifiedXpath"
    >> select="'/AAA/BBB/CCC/@DDD'"/>
    >> <!-- hardcoded namespace prefix -->
    >> <xsl:variable name="prefixString" select="'dns:'"/>
    >> <!-- hardcoded delimiter character -->
    >> <xsl:variable name="slash" select="'/'"/>
    >> <!-- Variable to contain the tokens -->
    >> <xsl:variable name="tokens">
    >> <!-- Calling tokenizer template-->
    >> <xsl:call-template name="tokenizer">
    >> <xsl:with-param name="string" select="$sampleUnqualifiedXpath"/>
    >> <xsl:with-param name="delimiter" select="$slash"/>
    >> </xsl:call-template>
    >> </xsl:variable>
    >> <!-- Variable to hold the qualified Xpath -->
    >> <xsl:variable name="qualXpath">
    >> <!-- Constructing the qualified Xpath-->
    >> <!-- Iterate through the returned token nodes -->
    >> <xsl:for-each select="$tokens/token">
    >> <!-- Add delimiter-->
    >> <xsl:value-of select="$slash"/>
    >> <!-- Add prefix only when token is an element name i.e. doesn't have the
    >> @ character -->
    >> <xsl:if test="not(contains(.,'@'))">
    >> <!-- Adding namespace prefix -->
    >> <xsl:value-of select="$prefixString"/>
    >> <!-- Add token's value -->
    >> <xsl:value-of select="."/>
    >> </xsl:if>
    >> </xsl:for-each>
    >> </xsl:variable>
    >> <!-- returning qualXpath variable -->
    >> <xsl:value-of select="$qualXpath"/>
    >> </xsl:template>
    >>
    >> where the tokens' usage in the loop declaration
    >> <xsl:for-each select="$tokens/token">
    >>
    >> is causing a Result Tree Fragment (RTF) error; I've googled to find out
    >> more about it but frankly don't understand the problem, and unsure what
    >> an alternative solution would be and hence seeking Wisdom of The Elders!
    >> :)
    >>
    >> BTW, the code snippet above might be buggy (hopefully not too much) as
    >> I've been stuck at this RTF error and hence unable to proceed. I suspect
    >> the usage of contains(.,'@'),
    >> where I intend to check the token node's value for a '@' character, is
    >> bit fishy. :)
    >>
    >> Many thanks!
    >>
    >> Regards,
    >>
    >> Bilal B.
    >>
    >>
    >>
    >>
    >>
    >> *** Sent via Developersdex http://www.developersdex.com ***

    >
    >
     
    Dimitre Novatchev, Oct 7, 2006
    #6
  7. Bilal

    Bilal Guest

    Hi Dimitre,
    Thanks for your input; your first reply seemed interesting, but as you
    pointed out it using EXSLT, which I can't use just yet as I'm limited to
    XSLT 1.0 only.

    Regards,

    Bilal B.


    *** Sent via Developersdex http://www.developersdex.com ***
     
    Bilal, Oct 9, 2006
    #7
  8. "Bilal" <> wrote in message
    news:452a07ce$0$25774$...
    > Hi Dimitre,
    > Thanks for your input; your first reply seemed interesting, but as you
    > pointed out it using EXSLT, which I can't use just yet as I'm limited to
    > XSLT 1.0 only.
    >
    > Regards,
    >
    > Bilal B.


    Then you could use one of the three vendor-dependent versions of FXSL
    1.x -- MSXML, Saxon or Xalan- dependent.

    Cheers,
    Dimitre Novatchev
     
    Dimitre Novatchev, Oct 10, 2006
    #8
  9. Xalan does implement the EXSLT library, I believe.

    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Joe Kesselman, Oct 10, 2006
    #9
  10. I understood him to say he was not ready yet to use EXSLT, not that his XSLT
    processor didn't support it.

    Cheers,
    Dimitre Novatchev


    "Joe Kesselman" <> wrote in message
    news:p...
    > Xalan does implement the EXSLT library, I believe.
    >
    > --
    > () ASCII Ribbon Campaign | Joe Kesselman
    > /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Dimitre Novatchev, Oct 10, 2006
    #10
  11. Bilal

    Bilal Guest

    Yes, Dimitri rightly got what I intended! Although I am using Xalan-J,
    but that is at the implementation end and I use XMLSpy for debugging
    purposes (as thats the XML tool I'm most familiar with, and is used by
    non-programmer colleagues :) and hence didn't want to rely on EXSLT etc.
    as the latter doesn't support it AFAIK.

    It's useful to know that Xalan does support EXSLT so I may use that
    for future work.

    Many thanks again!

    Regards,

    Bilal B.

    >I understood him to say he was not ready yet to use EXSLT, >not that

    his XSLT processor didn't support it.
    >
    >Cheers,
    >Dimitre Novatchev


    *** Sent via Developersdex http://www.developersdex.com ***
     
    Bilal, Oct 11, 2006
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stylus Studio
    Replies:
    0
    Views:
    736
    Stylus Studio
    Aug 3, 2004
  2. Benjamin Hillsley
    Replies:
    3
    Views:
    1,731
    Dimitre Novatchev
    Sep 25, 2003
  3. ted
    Replies:
    1
    Views:
    647
    Laurens
    Jan 26, 2004
  4. roadrunner
    Replies:
    1
    Views:
    255
    Gunnar Hjalmarsson
    Feb 8, 2006
  5. nick
    Replies:
    1
    Views:
    491
    David Mark
    Feb 13, 2011
Loading...

Share This Page