为什么这些xsl:当测试总是被评估为false时?

时间:2014-09-29 17:22:30

标签: xml xslt xpath

我有一个位于http://pastie.org/9604783

的xml文件

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

这些xsl:otherwise陈述的预期效果是以下

的一些变体

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

中的a:t的内容

输出应包含在哪个标记中的变体取决于祖先是<bodytext></bodytext>还是<p.sld>以及<p.notes>属性是否具有值1,2或3

这是我的XSL

lvl

这是所需的XML输出:

<?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>

2 个答案:

答案 0 :(得分:3)

尝试和修复这两个主要问题会导致XSLT按预期工作:

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

所有这一切,你可以通过利用变量和摆脱那些不必要的count(...) > 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>

答案 1 :(得分:0)

至少,ancestor::r看起来不对劲。至少OSX有一个perl实用程序xpath,你可以测试select statemtents。我必须将::r替换为::a: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. preceding...中的ancestor::r/preceding-sibling::node[1][@lvl='1']实际上应该是a:r的谓词,而不是a:r的路径

  2. count()函数是不必要的,正如我的XPath示例所证明的......最基本的XSL测试之一是“节点是否存在”(某些节点数> 0),所以{ {1}}隐含test="a"而不是所有......

  3. parens,看起来也搞砸了(例如,test="count(a) > 0",为什么最后一个paren的)) > 0" 之外?);只需取消> 0,直到您真正关心元素的确切数量