Using tokenize within a stylesheet used in a browser

跟風遠走 提交于 2021-02-08 08:32:05

问题


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:

  1. you don't need to import anything;
  2. you can (and should) use the function, not the template; and
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!