XSL:获取包含单独节点中任何单词的文本值

时间:2017-09-20 19:45:33

标签: xml xslt

如果文字包含<line><vehicleType>中的任何字词,我正试图在<color>中找到该文字。我还需要计算<vehicleType><color><description>中包含的单词数量。是否可以使用XSL(版本= 1.0)?

输出应如下所示:

Vehicle type (4)
This vehicle is a white <font color="red">compact car</font>.
This vehicle is a orange <font color="red">minivan</font>.
This vehicle is a red <font color="red">sedan</font>.
This vehicle is a yellow <font color="red">truck</font>.

Color (4)
This vehicle is a <font color="red">white</font> compact car.
This vehicle is a <font color="red">red</font> sedan.
This vehicle is a <font color="red">yellow</font> truck.
This vehicle is a <font color="red">yellow</font> crossover.

这是简化的xml:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test9.xsl"?>
<items>
    <vehicleTypes>
     <vehicleType>truck</vehicleType>
     <vehicleType>compace</vehicleType>
     <vehicleType>car</vehicleType>
     <vehicleType>sedan</vehicleType>
     <vehicleType>minivan</vehicleType>
    </vehicleTypes>
    <colors>
     <color>red</color>
     <color>yellow</color>
     <color>blue</color>
     <color>white</color>
     <color>purple</color>
     <color>gold</color>
     <color>silver</color>
    </colors>
    <item>
        <description>
            <p>
                <line>
                    This vehicle is a white compact car.
                </line>
                <line>
                    This vehicle is a orange minivan.
                </line>
                <line>
                    This vehicle is a red sedan.
                </line>
                <line>
                    This vehicle is a yellow truck.
                </line>
                <line>
                    This vehicle is a yellow crossover.
                </line>
            </p>
        </description>
    </item>
</items>

1 个答案:

答案 0 :(得分:0)

为了测试'vehicleType'或'color'中的任何逗号分隔值是否在当前元素中出现为空格或标点符号分隔的单词或短语,我会写出类似这样的内容(未经过测试):

<xsl:variable name="needles.vT" as="xs:string"
     select="tokenize(/items/vehicleType,',')"/>
<xsl:variable name="needles.c" as="xs:string"
     select="tokenize(/items/color,',')"/>
<xsl:variable name="haystack" as="xs:string"
     select="concat(' ',
                    normalize-space(
                      translate(.,
                         ' .,;:!?()-=+',
                         '            '),
                    ' ')"/>
<xsl:if test="some $needle in ($needles.vT, $needles.c)
              satisfies contains($haystack, 
                          concat(' ', $needle, ' ')">
  ... code for magic-word-found case ...
</xsl:if>

可能有更优雅的方式来做到这一点。

为了计算大海捞针中车型和彩色针数的数量,我会使用类似的东西

count($needles.vT[contains($haystack, concat(' ', ., ' '))])
count($needles.c[contains($haystack, concat(' ', ., ' '))])

在XSLT 1.0中,我编写了一个递归模板,该模板通过术语列表工作,剥离第一个术语,如果匹配则向累加器添加一个,并在术语列表的其余部分重复使用。一般形式是

<xsl:template name="countHits">
  <xsl:param name="needles"/><!--* terms to seek *-->
  <xsl:param name="haystack"/><!--* where to seek them *-->
  <xsl:param name="accumulator" select="0"/>
    <!--* number of hits so far *-->

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

  <xsl:choose>
    <xsl:when test="normalize-space($needles) = ''">
      <xsl:value-of select="$accumulator"/>
    </xsl:when>
    <xsl:when test="contains($haystack, concat(' ', $needle, ' ')">
      <xsl:call-template name="countHits">
        <xsl:with-param name="needles"
          select="substring-after($needles, ',')"/>
        <xsl:with-param name="haystack"
          select="$haystack"/>
        <xsl:with-param name="accumulator"
          select="1 + $accumulator"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="countHits">
        <xsl:with-param name="needles"
          select="substring-after($needles, ',')"/>
        <xsl:with-param name="haystack"
          select="$haystack"/>
        <xsl:with-param name="accumulator"
          select="$accumulator"/>
      </xsl:call-template>
    </xsl:otherwise>        
  </xsl:choose>
</xsl:template>

我假设你可以弄清楚如何准备$ haystack的初始值以及如何调用模板。

如果您对XML的形式有任何控制权,您可以考虑更改“vehicleType”和“color”以将单独的值放在单独的元素中,因此:

<colors>
  <color>red</color>
  <color>yellow</color>
  <color>blue</color>
  <color>white</color>
  <color>purple</color>
  <color>gold</color>
  <color>silver</color>
</colors>

然后测试变成类似下面的内容(使用$ haystack定义如上):

<xsl:variable name="colorcount"
     select="count(/items/colors/color
             [contains($haystack, concat(' ', ., ' ')])"/>

,类似于vehicleType。