471,082 Members | 904 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,082 software developers and data experts.

XSLT & String manipulation query

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 ***
Oct 6 '06 #1
10 5888
In article <45***********************@news.qwest.net>,
Bilal <no****@devdex.comwrote:
><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
Oct 6 '06 #2
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
Oct 6 '06 #3
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 ***
Oct 6 '06 #4
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:output 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" <no****@devdex.comwrote in message
news:45***********************@news.qwest.net...
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 ***

Oct 7 '06 #5
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" <di******@tpg.com.auwrote in message
news:45***********************@authen.yellow.readf reenews.net...
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:output 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" <no****@devdex.comwrote in message
news:45***********************@news.qwest.net...
>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 ***


Oct 7 '06 #6
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 ***
Oct 9 '06 #7

"Bilal" <no****@devdex.comwrote in message
news:45***********************@news.qwest.net...
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
Oct 10 '06 #8
Xalan does implement the EXSLT library, I believe.

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
Oct 10 '06 #9
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" <ke************@comcast.netwrote in message
news:pp******************************@comcast.com. ..
Xalan does implement the EXSLT library, I believe.

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry

Oct 10 '06 #10
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 ***
Oct 11 '06 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by J Trost | last post: by
5 posts views Thread by Per Johansson | last post: by
2 posts views Thread by chris | last post: by
9 posts views Thread by Ray | last post: by
1 post views Thread by jrwarwick | last post: by
4 posts views Thread by shaun roe | last post: by
11 posts views Thread by Ebenezer | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.