2

我对 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

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

4

2 回答 2

0

你很近。

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

如果您希望递归模板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元素会意外匹配不应删除的字符串的任何部分(例如,如果任何项目将具有值 '1',则原始字符串将永远不会具有像 '11' 这样的值)。

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

于 2012-09-14T18:23:40.813 回答
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:otherwisexsl:if

  2. 没有命名模板,也没有显式递归(尽管xsl:apply-templates隐式递归)。

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

于 2012-09-15T03:20:18.150 回答