问题
I'm trying to assign a variable a certain token from a large string. I first tokenize the string, then for each token I check if it contains a certain substring. If it does, I want to assign that token to the variable.
Lastly, I use that variable to set an attribute of a div.
I've tried this code below, which gives me the exact output i want in oXygen XML Editor
. However, when I run the XML/XSLT file in IE
(11), it simply just prints out the entire original string, meaing xhtmlVar
in the XSLT below. The div doesn't even show up (it might be there in DOM, but I don't visually see it -- I'll recheck this momentarily).
XSLT
<!-- xhtmlVar variable is a large string -->
<xsl:variable name="xhtmlVar" select="metadata[@element='xhtml_head_item']"></xsl:variable>
<xsl:variable name="quoteChar">"</xsl:variable> <!-- for cleaning token below -->
<xsl:variable name="tokenized" select="tokenize($xhtmlVar,' ')"/>
<xsl:variable name="doi">
<xsl:for-each select="$tokenized">
<xsl:variable name="curtoken" select="."/>
<!-- if token contains the string 'doi', assign it to the variable -->
<xsl:if test="contains($curtoken, 'doi')">
<!-- return value while stripping some stuff (token looks like this: doi:asdasdasd") -->
<xsl:value-of select="translate(replace($curtoken, 'doi:', ''),$quoteChar,'')"></xsl:value-of>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- pass $doi variable as attribute value in a div -->
<div type='medium' class='embed' handle='{$doi}'></div>
How can I achieve what I want? Am I doing something wrong? Any tips on how to more gracefully write the code above is also appreciated!
Thanks in advance!
Update:
I've changed my code to use EXSLT, as suggested by Martin Honnen below.
However, now the tokenize template seems to simply remove the specified delimiter instead of actually using it as a delimiter. Also, I can't figure out how to use a whitespace as a delimiter:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl str"
exclude-result-prefixes="xs"
version="1.0">
<xsl:import href="str/str.xsl" />
<xsl:import href="str.tokenize/str.tokenize.template.xsl" />
...
<xsl:variable name="quoteChar">"</xsl:variable>
<xsl:variable name="spaceChar"> </xsl:variable>
<xsl:variable name="tokenized">
<xsl:call-template name="str:tokenize">
<xsl:with-param name="string" select="$xhtmlVar" />
<xsl:with-param name="delimiters" select="','" />
</xsl:call-template>
</xsl:variable>
<!-- prevent tree fragment error with exsl:node-set -->
<xsl:for-each select="exsl:node-set($tokenized)">
<xsl:variable name="curtoken" select="."/>
<xsl:value-of select="$curtoken"/>
<xsl:text> Ha </xsl:text>
<!-- Nevermind checking if each token contains what I want for now...
<xsl:if test="contains($curtoken, 'doi')">
<xsl:value-of select="translate(str:replace($curtoken, 'doi:', ''),$quoteChar,'')"></xsl:value-of>
</xsl:if>-->
</xsl:for-each>
Instead of printing out each token separated by the word "Ha", the code above will print out the entire string (every token) but the comma delimiter "," will be removed. "Ha" then appears at the very end. Am I perhaps using the node-set
function incorrectly?
Also, if I try to use delimiters like $spaceChar
or an entire word, such as 'than'
, I often get something along the lines of a "template instruction stack overflow" error.
Code per michael.hor 's answer works.
Using, str:replace()
like so
<xsl:value-of select="translate(str:replace($curtoken, 'doi:', ''),$quoteChar,'')"/>
Gives me this error in oXygen XML, though:
Severity: fatal
Description: java.lang.NoSuchMethodException: For extension function, could not find method org.apache.xalan.lib.ExsltStrings.replace([ExpressionContext,] #NODESET, #STRING, #STRING).
Checked both static and instance methods. - For extension function, could not find method org.apache.xalan.lib.ExsltStrings.replace([ExpressionContext,] #NODESET, #STRING, #STRING).
Checked both static and instance methods.
回答1:
Re your updated question:
If your processor supports the EXSLT str:tokenize() extension function, then:
- you don't need to import anything;
- you can (and should) use the function, not the template; and
- the result of the function is already a node-set.
Try the following stylesheet as a test (it will work with any input):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="input" select="'some,comma,delimited,string'" />
<xsl:template match="/">
<xsl:variable name="tokenized" select="str:tokenize($input, ',')" />
<output>
<xsl:for-each select="$tokenized">
<xsl:value-of select="." />
<xsl:text> Ha </xsl:text>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
回答2:
tokenize
is not supported in XSLT/XPath 1.0 and that version is all that browsers support. If you want to use Xslt 2.0 in the browser then you need to look into Saxon CE.
Inside of IE the XSLT implementation is MSXML and for that http://exslt.org/str/functions/tokenize/index.html provides a tokenize implementation done with JScript.
来源:https://stackoverflow.com/questions/25168475/using-tokenize-within-a-stylesheet-used-in-a-browser