xml xsl:如何拆分字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4845660/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 13:32:09  来源:igfitidea点击:

xsl: how to split strings?

xmlxsltxslt-1.0xslt-2.0

提问by Jason S

I want to split an address on semicolons (;) into rows separated by <br />:

我想将分号 ( ;)上的地址拆分为由<br />以下分隔的行:

e.g. if address=123 Elm Street, I want to output 123 Elm Street,

例如,如果address= 123 Elm Street,我想输出123 Elm Street

but if address=123 Elm Street;PO Box 222, I want to output

但是如果address= 123 Elm Street;PO Box 222,我想输出

123 Elm Street<br />PO Box 222

and if address=123 Elm Street;PO Box 222;c/o James Jones, I want to output

如果address= 123 Elm Street;PO Box 222;c/o James Jones,我想输出

123 Elm Street<br />PO Box 222<br />c/o James Jones

Is there a way to do this? (probably easy but I'm not that familiar with XSLT)

有没有办法做到这一点?(可能很容易,但我对 XSLT 不太熟悉)

The plain XSL selector is

普通的 XSL 选择器是

<xsl:value-of select="address"/>

and I would like to modify this XSLT fragment to split on semicolon.

我想修改这个 XSLT 片段以在分号上拆分。



update: Apparently the answer involves the use of <xsl:call-template>and the functions substring-before()and substring-after().

更新:显然答案涉及使用<xsl:call-template>和功能substring-before()substring-after()

But I'm a beginner to XSLT and I could really use some help for how to do this.

但我是 XSLT 的初学者,我真的可以使用一些帮助来了解如何做到这一点。

回答by Dimitre Novatchev

I. Plain XSLT 1.0 solution:

一、纯XSLT 1.0解决方案:

This transformation:

这种转变

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>
  <xsl:if test="string-length($pText)">
   <xsl:if test="not($pText=.)">
    <br />
   </xsl:if>
   <xsl:value-of select=
    "substring-before(concat($pText,';'),';')"/>
   <xsl:call-template name="split">
    <xsl:with-param name="pText" select=
     "substring-after($pText, ';')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

应用于此 XML 文档时

<t>123 Elm Street;PO Box 222;c/o James Jones</t>

produces the wanted, corrected result:

产生想要的、更正的结果

123 Elm Street<br />PO Box 222<br />c/o James Jones

II. FXSL 1 (for XSLT 1.0):

二、FXSL 1(用于 XSLT 1.0):

Here we just use the FXSLtemplate str-map(and do not have to write recursive template for the 999th time):

这里我们只用了FXSL模板str-map(不用写第999次递归模板):

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:testmap="testmap"
exclude-result-prefixes="xsl f testmap"
>
   <xsl:import href="str-dvc-map.xsl"/>

   <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=
       "'123 Elm Street;PO Box 222;c/o James Jones'"/>
     </xsl:call-template>
   </xsl:template>

    <xsl:template name="replace" mode="f:FXSL"
         match="*[namespace-uri() = 'testmap']">
      <xsl:param name="arg1"/>

      <xsl:choose>
       <xsl:when test="not($arg1=';')">
        <xsl:value-of select="$arg1"/>
       </xsl:when>
       <xsl:otherwise><br /></xsl:otherwise>
      </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

when this transformation is applied on any XML document (not used), the same, wanted correct result is produced:

当此转换应用于任何 XML 文档(未使用)时,会产生相同的、想要的正确结果

123 Elm Street<br/>PO Box 222<br/>c/o James Jones

III. Using XSLT 2.0

三、使用 XSLT 2.0

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="text()">
  <xsl:for-each select="tokenize(.,';')">
   <xsl:sequence select="."/>
   <xsl:if test="not(position() eq last())"><br /></xsl:if>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on this XML document:

当此转换应用于此 XML 文档时

<t>123 Elm Street;PO Box 222;c/o James Jones</t>

the wanted, correct result is produced:

产生了想要的、正确的结果

123 Elm Street<br />PO Box 222<br />c/o James Jones

回答by Mormegil

If your XSLT processor supports EXSLT, you can use str:tokenize, otherwise, the link contains an implementation using functions like substring-before.

如果您的 XSLT 处理器支持EXSLT,您可以使用str:tokenize,否则,该链接包含使用 substring-before 之类的函数的实现。