xml xslt 1.0 中的拆分功能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7425071/
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 14:57:31  来源:igfitidea点击:

split function in xslt 1.0

xmlxslt

提问by Tom Cruise

how to split a node value in XSLT 1.0?

如何在 XSLT 1.0 中拆分节点值?

<mark>1,2</mark>

i need to perform some operations in the for loop with each value of the output of split.

我需要在 for 循环中使用 split 输出的每个值执行一些操作。

<xsl:for-each select=""> </xsl:for-each>

<xsl:for-each select=""> </xsl:for-each>

How to do this?

这该怎么做?

回答by Dimitre Novatchev

I. XSLT 1.0 solution:

一、XSLT 1.0 解决方案

Here is one way to do this in XSLT 1.0 using only the xxx:node-set()extension function:

这是在 XSLT 1.0 中仅使用xxx:node-set()扩展函数执行此操作的一种方法

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

 <xsl:template match="mark">
  <xsl:variable name="vrtfSplit">
   <xsl:apply-templates/>
  </xsl:variable>

  <xsl:for-each select="ext:node-set($vrtfSplit)/*">
   <processedItem>
    <xsl:value-of select="10 * ."/>
   </processedItem>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>
   <xsl:if test="string-length($pText) >0">
    <item>
     <xsl:value-of select=
      "substring-before(concat($pText, ','), ',')"/>
    </item>

    <xsl:call-template name="split">
     <xsl:with-param name="pText" select=
     "substring-after($pText, ',')"/>
    </xsl:call-template>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied to the following XML document:

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

<mark>1,2,3,4,5</mark>

The wanted, correct output (each item multiplied by 10) is produced:

产生想要的、正确的输出(每个项目乘以 10)

<processedItem>10</processedItem>
<processedItem>20</processedItem>
<processedItem>30</processedItem>
<processedItem>40</processedItem>
<processedItem>50</processedItem>

II. XSLT 2.0 solution:

二、XSLT 2.0 解决方案

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

 <xsl:template match="mark">
  <xsl:for-each select="tokenize(., ',')">
   <processedItem>
    <xsl:sequence select="10*xs:integer(.)"/>
   </processedItem>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

回答by Abhinav

The explaination by Dimitre Novatchev is awesome, but we can also do it in much more simpler way without using node-set()function have a look:

Dimitre Novatchev 的解释很棒,但我们也可以在不使用node-set()函数的情况下以更简单的方式来完成,看看:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">


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



    <xsl:variable name="delimiter">
        <xsl:text>,</xsl:text>
    </xsl:variable>



    <xsl:template match="mark">
        <xsl:variable name="dataList">
            <xsl:value-of select="."/>
        </xsl:variable>
        <xsl:call-template name="processingTemplate">
            <xsl:with-param name="datalist" select="$dataList"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="processingTemplate">
        <xsl:param name="datalist"/>


        <xsl:choose>
        <xsl:when test="contains($datalist,$delimiter)  ">
                <xsl:element name="processedItem">
                    <xsl:value-of select="substring-before($datalist,$delimiter) * 10"/>
                </xsl:element>
                <xsl:call-template name="processingTemplate">
                    <xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/>
                </xsl:call-template>
        </xsl:when>
            <xsl:when test="string-length($datalist)=1">
                <xsl:element name="processedItem">
                    <xsl:value-of select="$datalist * 10"/>

                    </xsl:element>
            </xsl:when>
        </xsl:choose>    

    </xsl:template>
</xsl:stylesheet>

回答by Michael Kay

In 1.0 you need to write a recursive template - except you don't, because it's already been written. Download the str:tokenizetemplate from http://www.exslt.org.

在 1.0 中,您需要编写一个递归模板 - 除非您不需要,因为它已经编写好了。从http://www.exslt.org下载str:tokenize模板。

回答by Jim Garrison

If you can use exslt there's a tokenize()function that will do this nicely.

如果您可以使用 exslt,那么有一个tokenize()函数可以很好地完成此操作。

node-set str:tokenize(string, string?)

See http://www.exslt.org/str/functions/tokenize/

http://www.exslt.org/str/functions/tokenize/

回答by Bluewood66

This code will split a delimited string in XSLT 1.0 (It will work for 2.0, but don't use the node-set.) It will also optionally suppress empty elements in the string or optionally upper case the elements.

此代码将在 XSLT 1.0 中拆分一个分隔的字符串(它适用于 2.0,但不使用节点集。)它还可以选择性地抑制字符串中的空元素或可选地大写元素。

<!-- Example delimited string. -->
<xsl:variable name="delimitedString" select="'a, b, c, ,   , d, e, f, g'"/>

<!-- Create a node set where each node contains one of the elements from the
     delimited string. -->
<xsl:variable name="splitNodes">
  <xsl:call-template name="getNodeListFromDelimitedList">
    <xsl:with-param name="inStrList" select="$delimitedString"/>
    <xsl:with-param name="delimiter" select="','"/>
    <xsl:with-param name="suppressEmptyElements" select="false()"/>
    <xsl:with-param name="upperCase" select="false()"/>
    <xsl:with-param name="allTrim" select="false()"/>
  </xsl:call-template>    
</xsl:variable>

<!-- Use this for XSLT 1.0 only. -->
<xsl:variable name="splitNodesList" select="msxml:node-set($splitNodes)"/>

<!-- Use the split node list to do something.  For example, create a string like 
     the delimited string, but without the delimiters. -->
<xsl:variable name="nonDelimitedString">
  <xsl:for-each select="$splitNodesList/element">
    <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:variable>


<!-- Do something with the nonDelimitedString. -->

<!-- 
*****************************************************************************************

This template converts a delimited string list to a node list as follows:

Each value in the delimited input string is extracted from the string.  Then, a node is 
created to contain the value.   The name of the node is 'element', and it is added to the 
list.  To use this template, create an variable and call this template from within the variable.
If you are using XSLT version 1.0, convert the node list to a node set using the node-set 
function.  You can access the element as follows:  $SomeVariableNodeSet/element

*****************************************************************************************
-->
<xsl:template name="getNodeListFromDelimitedList">
  <!-- Delimited string with one or more delimiters.  -->
  <xsl:param name="inStrList"/>
  <!-- The delimiter. -->
  <xsl:param name="delimiter" select="'|'"/>
  <!-- Set to true to suppress empty elements from being added to node list. Otherwise, set to 'false'.-->
  <xsl:param name="suppressEmptyElements" select="true()"/>
  <!-- Set to true to upper case the strings added to the node list.  -->
  <xsl:param name="upperCase" select="false()"/>
  <!-- Set to true to left trim and right trim the strings added to the nodes list.  -->
  <xsl:param name="allTrim" select="false()"/>

  <xsl:variable name="element">
    <xsl:choose>
      <xsl:when test="contains($inStrList,$delimiter)">
        <xsl:value-of select="substring-before($inStrList,$delimiter)"/> 
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$inStrList"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- Write out the element based on parameters. -->
  <xsl:if test="not($suppressEmptyElements) or normalize-space($element) != ''">
    <!-- Put the element in the list.  -->
    <xsl:element name="element">
      <xsl:choose>
        <xsl:when test="$allTrim">
          <xsl:call-template name="all-trim">
            <xsl:with-param name="inStr" select="$element"/>
            <xsl:with-param name="upperCase" select="$upperCase"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:when test="$upperCase">
          <xsl:value-of select="translate($element, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$element"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:if>

  <xsl:if test="contains($inStrList,$delimiter)">
    <!-- Call template recursively to process the next element. -->
    <xsl:call-template name="getNodeListFromDelimitedList">
      <xsl:with-param name="inStrList" select="substring-after($inStrList,$delimiter)"/>
      <xsl:with-param name="delimiter" select="$delimiter"/>
      <xsl:with-param name="suppressEmptyElements" select="$suppressEmptyElements"/>
      <xsl:with-param name="upperCase" select="$upperCase"/>
      <xsl:with-param name="allTrim" select="$allTrim"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>


<!-- 
*****************************************************************************************
This template trims the blanks from the left and right sides of a string. 
*****************************************************************************************
-->
<xsl:template name="all-trim">
  <!-- The string that you want to all trim. -->
  <xsl:param name="inStr"/>
  <xsl:param name="upperCase" select="false()"/>

  <xsl:variable name="leftTrimmed">
    <xsl:call-template name="left-trim">
      <xsl:with-param name="inStr" select="$inStr"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="rightTrimmed">
    <xsl:call-template name="right-trim">
      <xsl:with-param name="inStr" select="$leftTrimmed"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="$upperCase">
      <xsl:value-of select="translate($rightTrimmed, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$rightTrimmed"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- 
*****************************************************************************************
This template trims the blanks from the left side of a string. 
*****************************************************************************************
-->
<xsl:template name="left-trim">
  <!-- The string you want to left trim.  -->
  <xsl:param name ="inStr"/>

  <xsl:choose>
    <xsl:when test="$inStr!=''">
      <xsl:variable name="temp" select="substring($inStr, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="$temp=' '">
          <xsl:choose>
            <xsl:when test="string-length($inStr) &gt; 1">
              <xsl:call-template name="left-trim">
                <xsl:with-param name="inStr" select="substring($inStr, 2, string-length($inStr)-1)"/>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="''"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$inStr"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="''"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!--
*****************************************************************************************
This template trims the blanks from the right side of a string. 
*****************************************************************************************
-->
<xsl:template name="right-trim">
  <!-- The string you want to right trim.  -->
  <xsl:param name ="inStr"/>

  <xsl:choose>
    <xsl:when test="$inStr!=''">
      <xsl:variable name="temp" select="substring($inStr, string-length($inStr), 1)"/>
      <xsl:choose>
        <xsl:when test="$temp=' '">
          <xsl:choose>
            <xsl:when test="string-length($inStr) &gt; 1">
              <xsl:call-template name="right-trim">
                <xsl:with-param name="inStr" select="substring($inStr, 1, string-length($inStr)-1)"/>
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="''"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$inStr"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="''"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>