【问题标题】:XSLT filtering nodes on conditional logicXSLT 在条件逻辑上过滤节点
【发布时间】:2011-10-30 08:19:10
【问题描述】:

我有一个源 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 可以用于此吗?

【问题讨论】:

  • 这是作业吗?这对我来说似乎是一个家庭作业问题。
  • 您应该发布您已经拥有的 XSLT 代码...
  • 我是 XSLT 的新手。我使用的是完全错误的。我正在使用变量并尝试在 for-each 循环中更改变量的值。谷歌搜索后,我发现无法更改 xslt 中变量的值。所以那个不是什么好东西。
  • 好问题,+1。请参阅我的答案以获得更好的解决方案,该解决方案允许将优先主题作为参数传递。此外,随着优先主题列表的增加,转换的复杂性和模板数量不会增加。 :) 您还可以轻松解决类似的问题:“显示优先列表中的前两个主题”。

标签: xslt


【解决方案1】:

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

<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)]
  " />

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

【讨论】:

    【解决方案2】:

    这是一个更简单的解决方案,适用于任意数量的优先主题,并且只使用一个固定大小的模板它可以很容易地用于更困难的问题,例如:“仅显示N 主题的优先列表中的第一个 k 主题“:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多