XSLT如何检查XML节点是否存在?

16

我有一个XML文件:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<Data>
  <Records>
    <Record>
     <AddInfo>
      <Info>
      </Info>
     </AddInfo>
    </Record>
  </Records>
</Data>

和 XSL 文件:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="Dane">
    <html>
      <link rel="stylesheet" type="text/css" href="report.css"></link>
      <body>
        <h2>Table1</h2>
        <table border="1" cellspacing="0">
          <tr>
            <th>XXX</th>
          </tr>
          <xsl:for-each select="Records/Record">
            <tr>
              <td>
                <xsl:value-of select="XXX"/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
        <h2>SecondTable</h2>
        <table border="1" cellspacing="0">
          <tr>
            <th>YYY</th>
            <th>ZZZ</th>
          </tr>
          <xsl:for-each select="Records/Record/AddInfo/Info">
            <tr>
              <td>
                <xsl:value-of select="YYY"/>
              </td>
              <td>
                <xsl:value-of select="ZZZ"/>
              </td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
如果节点存在,则显示带有“Info”节点的表格,如果不存在,则显示一些文本。
我一直在尝试。
<xsl:if test="following-sibling::AddInfo">
</xsl:if>

<xsl:if test="AddInfo">
</xsl:if>

但是它没有起作用。

我想要它像这样:

Table1
---------------------
|     |      |      |

(条件:如果XML中存在<node>元素,则我希望在Table1下方显示第二个表格。)

SecondTable
-------------
|     |     |

我该怎么做?


1
不清楚您的问题是什么。有一件重要的事情,您没有发布您期望的输出。请在输入的XML中列出您想要处理的所有情况。 - Lingamurthy CS
1
你的问题不够清晰。你想在哪里插入这个测试?你只有一个通用表格,所以“如果节点存在,则显示带有“信息”节点的表格;如果不存在,则显示一些文本”几乎没有意义。 - michael.hor257k
那么,您是在说如果addInfo元素不存在,则应显示某些文本吗? - Rnet
是的,我绝对想要像Rnet说的那样。 - vBB
“if inside XML will be node” 是什么意思?你是想说“如果某个节点存在就执行这个操作”吗? - Rnet
@vBB XSLT没有if-else结构,你需要使用choose,并在choose的默认情况下编写“else”条件,就像CoDEmanX所示的那样。 - Rnet
2个回答

32

如果<Record>的直接子元素中存在<AddInfo>,则输出Yep,否则输出Nope

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="Data">
    <xsl:for-each select="Records/Record">
      <xsl:choose>
        <xsl:when test="AddInfo">Yep</xsl:when>
        <xsl:otherwise>Nope</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

请注意,您不需要使用for-each,您应该让第二个模板匹配每个<Record>

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="Data">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="Data/Records/Record">
    <xsl:choose>
      <xsl:when test="AddInfo">Yep</xsl:when>
      <xsl:otherwise>Nope</xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

您也可以避免使用choose,而是使用两个独立的if条件:

  <xsl:template match="Data/Records/Record">
    <xsl:if test="AddInfo">Yep</xsl:if>
    <xsl:if test="not(AddInfo)">Nope</xsl:if>
  </xsl:template>
如果不想仅限于立即子元素,请改用.//AddInfo
考虑以下样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="Data">
    <xsl:apply-templates select="Records/Record"/>
  </xsl:template>

  <xsl:template match="Data/Records/Record">
    <table class="one"></table>
    <xsl:if test="AddInfo">
      <table class="two"></table>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

它输出

<table class="one"></table>

如果在<Record>节点中不存在<AddInfo>节点,那么

<table class="one"></table>
<table class="two"></table>

否则。

你可以通过不使用ifchoose来解决此问题。XML:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<Data>
  <AddInfo>
    <Info>This is ignored</Info>
  </AddInfo>
  <Records>
    <Record>
        <AddInfo>
          <Info>One,</Info>
          <Info>Two,</Info>
          <Info>Three</Info>
        </AddInfo>
    </Record>
    <Record>
      <Info>Ignored as well</Info>
    </Record>
    <Record>
      <Nested>
        <AddInfo>
          <Info>So is this</Info>
        </AddInfo>
      </Nested>
    </Record>
  </Records>
</Data>

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="Data">
    <root>
      <xsl:apply-templates select="Records/Record"/>
    </root>
  </xsl:template>

  <xsl:template match="Data/Records/Record">
    <xsl:copy>
      <table id="one"></table>
      <xsl:apply-templates select="AddInfo"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Data/Records/Record/AddInfo">
    <table id="two">
      <xsl:apply-templates select="Info"/>
    </table>
  </xsl:template>

  <xsl:template match="Data/Records/Record/AddInfo/Info">
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>

输出:

<root>
  <Record>
    <table id="one" />
    <table id="two">One,Two,Three</table>
  </Record>
  <Record>
    <table id="one" />
  </Record>
  <Record>
    <table id="one" />
  </Record>
</root>

看起来我已经测试了类似这样的东西,但它不起作用,因为如果在生成的XML中没有“AddInfo”节点,则仍会显示SecondTable(YYY,ZZZ)的标题,而我想显示一些文本代替此标题。 - vBB
条件节点需要包装所有生成第二个表的节点。请查看我的更新答案。 - CodeManX
1
好的代码。只有一个小建议:如果你很了解输入结构,就没必要在模板匹配中打出整个元素层次结构(例如 Data/Records/Record/AddInfo/Info)。 - Mathias Müller
确保不会从其他路径匹配到同名节点,这是正确的做法。不确定是否会影响性能。 - CodeManX
这就是我所说的。例如,只有当“Info”可能出现为除“AddInfo”之外的其他元素的子元素时,您才需要Data/Records/Record/AddInfo/Info。否则,性能没有区别。除此之外,您的代码是非常优秀的。 - Mathias Müller
我有一个CMS集合(在Ektron中),其中包含多个智能表单。每个智能表单都不同,我正在检查是否存在/为空的节点(如果存在),但它没有正常工作。 - SearchForKnowledge

2

要检查XML中是否存在节点,可以使用以下XSLT代码:

<xsl:choose>
                <xsl:when test="XMLNodeName">
                  <Cell ss:Index="2" ss:StyleID="s110">
                    <Data ss:Type="String">
                      <xsl:value-of select="NodeOne"/>
                    </Data>
                  </Cell>
                </xsl:when>
                <xsl:otherwise>
                  <Cell`enter code here` ss:Index="2" ss:StyleID="s110">
                    <Data ss:Type="String">
                      <xsl:value-of select="NodeTwo"/>
                    </Data>
                  </Cell>
                </xsl:otherwise>
 </xsl:choose>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接