如何根据搜索多个节点值删除多个数字?

时间:2012-09-14 17:43:00

标签: xslt xslt-1.0

我是XSLT的新手,已经扫描了几个关于该主题的帖子,但似乎无法获得我需要做的最终工作。我试图从我拥有的节点数据中出现的已知数据字符串中删除条目。我已经找到了一个适用于单节点值而不是多个值的解决方案。

这是我的xml

<root>
<item>2</item>
<item>9</item>
<item>5</item>
</root>

这是我的代码,适用于一个节点值:

<xsl:template match="item">
<xsl:copy>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="replaceChars">
<xsl:param name="original"/>
<xsl:choose>
<xsl:when test="contains($original, current())">
<xsl:value-of select="substring-before($original, current())"/>
<xsl:variable name="after" select="substring-after($original, current())"/>
<xsl:variable name="char" select="substring-before($after, current())"/>
<xsl:value-of select="concat($char, $after)"/>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="substring-after($after, current())"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$original"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

我最近的测试我试图使用它:

<xsl:template match="item">
<xsl:copy>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="replaceChars">
<xsl:param name="original"/>
<xsl:choose>
<xsl:when test="contains($original, current())">
<xsl:variable name="before" select="substring-before($original, current())"/>
<xsl:variable name="after" select="substring-after($original, current())"/>
<xsl:variable name="char" select="substring-before($after, current())"/>
<xsl:variable name="new" select="concat($before, $after)"/>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="$new"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$original"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

我决定在响应中多次重复该值。我希望我的输出如下:

1 3 4 6 7 8 10

我已经对此进行了广泛的搜索,因为您可以看到我的示例基于更改的搜索方案。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

你很亲密。

如果您想生成一次字符串“1 3 4 6 7 8 10”,那么您可能不希望为每个item元素评估您显示的代码一次,但每个root一次{1}}元素。

如果您希望递归模板replaceChars删除兄弟item元素集中每个item的值,那么当前结构将不会执行此操作。为什么?因为它会剔除current()的值,然后递归调用而不做任何改变current() 的值。

另一种方法是说“我想构建一个由数字1组成的字符串(除非它出现在输入中),然后是数字2(除非它出现在输入中),然后是...... “并写(未经测试):

<xsl:template match="root">
  <survivors>
    <xsl:if test="not(./item = '1')">1 </xsl:if> 
    <xsl:if test="not(./item = '2')">2 </xsl:if> 
    <xsl:if test="not(./item = '3')">3 </xsl:if> 
    <xsl:if test="not(./item = '4')">4 </xsl:if> 
    <xsl:if test="not(./item = '5')">5 </xsl:if> 
    <xsl:if test="not(./item = '6')">6 </xsl:if> 
    <xsl:if test="not(./item = '7')">7 </xsl:if> 
    <xsl:if test="not(./item = '8')">8 </xsl:if> 
    <xsl:if test="not(./item = '9')">9 </xsl:if> 
  </survivors>
</xsl:template>

或者,如果你真的想做子串匹配的事情,你需要确保replaceChars中的递归实际上迭代item个元素:

<xsl:template match="root">
  <survivors>
    <xsl:call-template name="replaceChars2">
      <xsl:with-param name="s" select="'1 2 3 4 5 6 7 8 9'"/>
      <xsl:with-param name="item" select="./item[1]"/>
    </xsl:call-template>
  </survivors>
</xsl:template>

<xsl:template name="replaceChars2">
  <xsl:param name="s"/>
  <xsl:param name="item"/>
  <xsl:variable name="s2" select="string($item)"/>
  <xsl:choose>
    <xsl:when test="$item">
      <xsl:call-template name="replaceChars2">
        <xsl:with-param name="s" 
          select="concat(
            substring-before($s,$s2,
            ' ',
            substring-after($s,$s2,
            )"/>
        <xsl:with-param name="item" 
          select="./following-sibling::item[1]"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$s"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

与OP显示的代码一样,这假设没有item元素会意外地匹配不应删除的字符串的任何部分(例如,如果任何项目,原始字符串将永远不会有像'11'的值将永远有值'1'。

迭代兄弟姐妹并传递参数以跟踪早期兄弟姐妹所发生的事情的模式是学习的重要习惯,对于像这样的变换。

答案 1 :(得分:0)

此转化

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output method="text"/>

 <my:sent/>
 <xsl:variable name="vSent" select="document('')/*/my:sent"/>

 <xsl:param name="pGiven" select="'1 2 3 4 5 6 7 8 9 10'"/>

 <xsl:template match="/*">
  <xsl:apply-templates select="item[1]"/>
 </xsl:template>

 <xsl:template match="item">
  <xsl:param name="pText" select="$pGiven"/>

  <xsl:apply-templates select=
   "following-sibling::item[1]|$vSent[not(current()/following-sibling::item)]">
    <xsl:with-param name="pText" select=
    "concat(substring-before(concat($pText, .), .),
            substring-after($pText,.)
            )
    "/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="my:sent">
  <xsl:param name="pText"/>
  <xsl:value-of select="$pText"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<root>
    <item>2</item>
    <item>9</item>
    <item>5</item>
</root>

会产生想要的正确结果:

1  3 4  6 7 8  10

请注意

  1. 整个转换中没有XSLT条件指令 - 没有xsl:choose,没有xsl:when,没有xsl:otherwise没有{{1} }。

  2. 没有命名模板,也没有显式递归(虽然xsl:if隐式递归)。

  3. Sentinel编程以两种不同的方式显着简化代码并提高效率。