条件逻辑上的XSLT过滤节点

时间:2011-08-19 05:31:06

标签: xslt

我有一个Source XML如下: -

<StudentSet>
 <Student>
  <StudentName>Kapil</StudentName>
  <Subject>English</Subject>
  <Subject>History</Subject>
  <Subject>Mathematics</Subject>
  <Subject>Economics</Subject>
 </Student>
 <Student>
  <StudentName>Atul</StudentName>
  <Subject>English</Subject>
  <Subject>History</Subject>
  <Subject>Economics</Subject>
 </Student>
 <Student>
  <StudentName>Nisha</StudentName>
  <Subject>English</Subject>
  <Subject>History</Subject>
 </Student>
 <Student>
  <StudentName>Manish</StudentName>
 </Student>
</StudentSet>

要应用的规则如下。

1)如果学生已注册数学,则显示学生姓名和数学

2)如果一个学生注册了经济学但没有注册数学,那就显示学生姓名和经济学

3)如果学生既没有注册数学和经济学,请选择学生姓名和任何一个科目。

4)如果学生没有注册任何科目,请不要选择该学生。

我想获得以下输出: -

<StudentSet>
 <Student>
  <StudentName>Kapil</StudentName>
  <Subject>Mathematics</Subject>
 </Student>
 <Student>
  <StudentName>Atul</StudentName>
  <Subject>Economics</Subject>
 </Student>
 <Student>
  <StudentName>Nisha</StudentName>
  <Subject>English</Subject>
 </Student>
</StudentSet>

请问有人可以帮助XSLT使用吗?

2 个答案:

答案 0 :(得分:4)

简单的方法就是使用带有谓词的模板,如下所示:

<xsl:template match="Student[Subject='Economics']">
  <!-- Handle economics students -->
</xsl:template>

<xsl:template match="Student[Subject='Mathematics']">
  <!-- Handle maths students -->
  <!-- overrides maths+econ students, as it comes later -->
</xsl:template>

<xsl:template match="Student[not(Subject='Economics') and not(Subject='Mathematics')]">
  <!-- Handle other students. Use 'Subject[1]' to refer to first subject -->
</xsl:template>

<!-- Handle students with no subject, outputting nothing. -->
<xsl:template match="Student[not(Subject)]" />

在每种情况下,您可能都想

<xsl:copy> <!-- copies the 'Student' element -->
  <xsl:copy-of select="StudentName" />
  <xsl:copy-of select="Subject[text()='subjectname']" />
  <!-- or -->
  <xsl:copy-of select="Subject[1]" /> <!-- first subject in list -->
</xsl:copy>

这是一种更短,更有效的方式,但对于初学者来说理解起来有点困难:

<xsl:template match="Student[Subject='Mathematics']/Subject[not(text()='Mathematics')]" />
<xsl:template match="Student[Subject='Economics' and not(Subject='Mathematics')]/Subject[not(text()='Economics')]" />
<xsl:template match="Student[not(Subject='Economics') and not(Subject='Mathematics')]/Subject[position() != 1]" />
<xsl:template match="Student[not(Subject)]" />

这些操作描述了不应输出的元素。例如,第一个找到具有数学主题的任何Student元素,并且在其中找到没有“数学”文本的任何Subject元素。模板匹配这些节点,并且不输出任何内容。您实际上可以使用一个大型模板规则执行此操作:

<xsl:template match="
  Student[Subject='Mathematics']/Subject[not(text()='Mathematics')]
| Student[Subject='Economics' and not(Subject='Mathematics')]/Subject[not(text()='Economics')]
| Student[not(Subject='Economics') and not(Subject='Mathematics')]/Subject[position() != 1]
| Student[not(Subject)]
  " />

虽然这样做开始变得不那么可读。

答案 1 :(得分:0)

这是一个更简单的解决方案,适用于任意数量的优先主题,并且只使用固定大小的单个模板它可以轻松用于更加困难的问题:“仅显示来自k科目的优先级列表中的第一个N科目:

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

 <xsl:param name="vSubs" select="'x|Economics|Mathematics|'"/>

 <xsl:template match="Student[Subject]">
     <Student>
      <xsl:copy-of select="StudentName"/>

      <xsl:for-each select="Subject">
       <xsl:sort
         select="string-length(substring-before($vSubs,
                                                concat('|',.,'|')
                                                )
                             )"
       data-type="number" order="descending"/>
       <xsl:if test="position()=1">
        <xsl:copy-of select="."/>
       </xsl:if>
      </xsl:for-each>
     </Student>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的XML文档

<StudentSet>
    <Student>
        <StudentName>Kapil</StudentName>
        <Subject>English</Subject>
        <Subject>History</Subject>
        <Subject>Mathematics</Subject>
        <Subject>Economics</Subject>
    </Student>
    <Student>
        <StudentName>Atul</StudentName>
        <Subject>English</Subject>
        <Subject>History</Subject>
        <Subject>Economics</Subject>
    </Student>
    <Student>
        <StudentName>Nisha</StudentName>
        <Subject>English</Subject>
        <Subject>History</Subject>
    </Student>
    <Student>
        <StudentName>Manish</StudentName>
    </Student>
</StudentSet>

产生了想要的正确结果

<Student>
   <StudentName>Kapil</StudentName>
   <Subject>Mathematics</Subject>
</Student>
<Student>
   <StudentName>Atul</StudentName>
   <Subject>Economics</Subject>
</Student>
<Student>
   <StudentName>Nisha</StudentName>
   <Subject>English</Subject>
</Student>