【问题标题】:Why do these xsl:when tests always get evaluated as false?为什么这些 xsl:when 测试总是被评估为假?
【发布时间】:2014-09-29 17:22:29
【问题描述】:

我有一个 xml 文件,位于 http://pastie.org/9604783

我将以下 xsl 与 Saxon-HE 一起使用,虽然它不会产生错误(因此它应该是正确的语法),但没有一个 xsl:when 语句似乎被评估为 true,因为所有输出标签都被包装在<bodytext></bodytext> 根据xsl:otherwise 声明。

这些xsl:when 语句的预期效果是以下的一些变体

如果a:t 元素有 一个<p.sld>祖先 AND 有一个 <r> 祖先,它有一个紧跟在前面的兄弟元素,它有一个属性:值对 lvl='1' 然后输出包裹在<bulleted></bulleted> 中的a:t 的内容 OTHERWISE 输出包裹在<bodytext></bodytext> 中的a:t 的内容

输出应包含在什么标签中的变化取决于祖先是 <p.sld> 还是 <p.notes> 以及 lvl 属性的值是 1、2 还是 3

这是我的 XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
  <xsl:output method="xml"/>

  <xsl:template match="/">
    <document>
      <xsl:apply-templates select="//a:t"/>
    </document>
  </xsl:template>

  <xsl:template match="//a:t">
    <xsl:choose>
      <xsl:when test="(count(ancestor::p:sld) > 0) and (count(ancestor::r/preceding-sibling::node[1][@lvl='1'])) > 0">
        <bulleted>
          <xsl:value-of select="."/>
        </bulleted>
      </xsl:when>
      <xsl:when test="(count(ancestor::p:sld) > 0) and (count(ancestor::r/preceding-sibling::node[1][@lvl='2'])) > 0">
        <bulleted2>
          <xsl:value-of select="."/>
        </bulleted2>
      </xsl:when>
      <xsl:when test="(count(ancestor::p:notes) > 0) and (count(ancestor::r/preceding-sibling::node[1][@lvl='2'])) > 0">
        <bulleted>
          <xsl:value-of select="."/>
        </bulleted>
      </xsl:when>
      <xsl:when test="(count(ancestor::p:notes) > 0) and (count(ancestor::r/preceding-sibling::node[1][@lvl='3'])) > 0">
        <bulleted2>
          <xsl:value-of select="."/>
        </bulleted2>
      </xsl:when>
      <xsl:otherwise>
        <bodytext>
          <xsl:value-of select="."/>
        </bodytext>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

这是所需的 XML 输出:

<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
    <bodytext>header text</bodytext>
    <bodytext>body text </bodytext>
    <bodytext>body text </bodytext>
    <bodytext>body text </bodytext>
    <bulleted>bulleted text</bulleted>
    <bulleted>bulleted text</bulleted>
    <bulleted>bulleted text</bulleted>
    <bulleted2>bulleted2 text</bulleted2>
    <bulleted2>bulleted2 text</bulleted2>
    <bulleted2>bulleted2 text</bulleted2>
    <bulleted2>bulleted2 text</bulleted2>
    <bulleted>bulleted text</bulleted>
    <bulleted>bulleted text</bulleted>
    <bulleted>bulleted text</bulleted>
    <bulleted>bulleted text</bulleted>
    <bodytext>body text</bodytext>
    <bodytext>body text</bodytext>
    <bodytext>footer text</bodytext>
    <bodytext>10</bodytext>
    <bodytext>10</bodytext>
    <bodytext>notes header text</bodytext>
    <bodytext>notes body text </bodytext>
    <bodytext>notes body text </bodytext>
    <bodytext>notes table header text</bodytext>
    <bodytext>notes table header text</bodytext>
    <bodytext>notes table body text</bodytext>
    <bodytext>notes table body text</bodytext>
    <bodytext>notes table body text</bodytext>
    <bodytext>notes table body text</bodytext>
    <bodytext>notes table body text</bodytext>
    <bodytext>notes table body text</bodytext>
</document>

【问题讨论】:

  • 请将您的示例最小化为仅演示问题所必需的部分。
  • 那会很有帮助。

标签: xml xslt xpath


【解决方案1】:

您的尝试存在两个主要问题,修复这些问题应该会导致 XSLT 按预期工作:

  • 您缺少ancestor::r 上的命名空间前缀。应该是ancestor::a:r
  • 您使用的是preceding-sibling::node 而不是preceding-sibling::node()。前者只会选择名为“node”的元素,其中没有。
    • 但是,您实际上应该使用 preceding-sibling::* 而不是这两个中的任何一个,以免空白文本节点妨碍您。

话虽如此,您的方法可以通过使用变量并摆脱不必要的count(...) &gt; 0 东西来清理很多。以下应该会产生预期的输出:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
  <xsl:output method="xml"/>

  <xsl:template match="/">
    <document>
      <xsl:apply-templates select="//a:t"/>
    </document>
  </xsl:template>

  <xsl:template match="a:t">
    <xsl:variable name="sld" select="ancestor::p:sld" />
    <xsl:variable name="notes" select="ancestor::p:notes" />
    <xsl:variable name="levelBeforeR"
                  select="ancestor::a:r/preceding-sibling::*[1]/@lvl" />

    <xsl:variable name="wrapperName">
      <xsl:choose>
        <xsl:when test="$sld   and $levelBeforeR = '1' or
                        $notes and $levelBeforeR = '2'">
          <xsl:text>bulleted</xsl:text>
        </xsl:when>
        <xsl:when test="$sld   and $levelBeforeR = '2' or
                        $notes and $levelBeforeR = '3'">
          <xsl:text>bulleted2</xsl:text>
        </xsl:when>
        <xsl:otherwise>bodytext</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:element name="{$wrapperName}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

【讨论】:

  • 谢谢!作为后续是否有一种简单的方法来扩展它以包装每个 p:sld 的第一个 a:t 后代的内容与标签 &lt;foo&gt; 和每个 p:notes 的第一个 a:t 后代的内容与标签&lt;bar&gt;?这而不是(不是添加到)通常应用的其他包装标签。
  • 决定将其作为全新的问题发布。见link
【解决方案2】:

至少,ancestor::r 看起来不对。至少 OSX 有一个 perl 实用程序,xpath,您可以测试 select 语句。我不得不用::a:r 替换::r,因为您的源XML 中没有r 节点:

~ zyoung$ xpath so.xml "//a:t[ancestor::p:sld and ancestor::r]"
No nodes found
~ zyoung$ xpath so.xml "//a:t[ancestor::p:sld and ancestor::a:r]"
Found 18 nodes:
-- NODE --
<a:t>header text</a:t>-- NODE --
<a:t>body text </a:t>-- NODE --
<a:t>body text </a:t>-- NODE --
<a:t>body text </a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted2 text</a:t>-- NODE --
<a:t>bulleted2 text</a:t>-- NODE --
<a:t>bulleted2 text</a:t>-- NODE --
<a:t>bulleted2 text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>bulleted text</a:t>-- NODE --
<a:t>body text</a:t>-- NODE --
<a:t>body text</a:t>-- NODE --
<a:t>footer text</a:t>

不做任何工作,我猜:

  1. ancestor::r/preceding-sibling::node[1][@lvl='1'] 中的preceding... 实际上应该是a:r 的谓词,而不是a:r 的路径

  2. count() 函数是不必要的,正如我的 XPath 示例所证明的那样……最基本的 XSL 测试之一是“节点是否存在”(某些节点数 > 0),所以 test="a" 意味着test="count(a) &gt; 0" 没有所有...

  3. 括号,看起来也乱七八糟(例如,)) &gt; 0",为什么&gt; 0 在最后一个括号之外?);只需取消count(),直到您真正关心元素的确切数量

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 2018-07-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多