xml - 根据 XSL 中的条件动态输出元素?

标签 xml xslt transform xslt-2.0

假设以下 xml 输入...

<incidents>
       <incident>
              <year>2011</year>
              <other data here>
       </incident>
       <incident>
              <year>2009</year>
              <other data here>
       </incident>
       <incident>
              <year>2006</year>
       </incident>
</incidents>

xml 始终按年份进行预排序,因此最新的事件年份位于第一个。我需要使用 xsl 处理它,并基本上以最小的变换输出 5 年前的数据,最多,但如果缺少任何年份,我只需要输出 <incident><year>missingYear</year></incident> 的元素。 .

所以,假设我有正确的 XSL 来执行此操作,处理上述 xml 将产生以下结果...

<incidents>
   <incident>
      <year>2011</year>
   </incident>
   <incident>
      <year>2010</year>
   </incident>
   <incident>
      <year>2009</year>
   </incident>
   <incident>
      <year>2008</year>
   </incident>
   <incident>
      <year>2007</year>
   </incident>
   <incident>
      <year>2006</year>
   </incident>
</incidents>

我已经使用 xsl 做到了这一点,但它并没有考虑到年份之间的巨大差距

<xsl:variable name="maxYear" select="/incidents/incident/year[1]"></xsl:variable>

<xsl:template match="incidents" >
  <xsl:element name="incident">           
    <xsl:for-each select="incident">                
      <xsl:variable name="currentYear" select="year"/>              

         <xsl:choose>
           <xsl:when test="($maxYear - (position() -1)) != $currentYear">
             <!-- output the missing year -->
             <xsl:element name="year"> <xsl:value-of select="($maxYear - (position() -1))" /></xsl:element>
             <!-- output the current year node -->
             <xsl:element name="year"> <xsl:value-of select="$currentYear" /></xsl:element>
            </xsl:when>
            <xsl:otherwise>
              <xsl:element name="year"> <xsl:value-of select="$currentYear" /></xsl:element>             
            </xsl:otherwise>           
         </xsl:choose>                     
    </xsl:for-each>       
  </xsl:element>
</xsl:template>

最佳答案

我。这是一个完整的 XSLT 1.0 解决方案:

<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="pYearsBack" select="6"/>
 <xsl:param name="pThisYear" select="2012"/>

 <xsl:variable name="vEarliest" select=
  "$pThisYear - $pYearsBack"/>

 <xsl:variable name="vYears" select="/*/*/year"/>

 <xsl:template match="/">
  <incidents>
    <xsl:call-template name="genYears"/>
  </incidents>
 </xsl:template>

 <xsl:template name="genYears">
  <xsl:param name="pTimes" select="$pYearsBack+1"/>
  <xsl:param name="pStart" select="$pThisYear"/>

  <xsl:if test="$pTimes > 0">
   <incident>
     <year>
      <xsl:value-of select=
      "concat($vYears[. = $pStart],
              substring('missingYear',
                         1 div not($vYears[. = $pStart]))
             )
      "/>
     </year>
   </incident>

   <xsl:call-template name="genYears">
    <xsl:with-param name="pTimes" select="$pTimes -1"/>
    <xsl:with-param name="pStart" select="$pStart -1"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时(已更正为格式良好):

<incidents>
    <incident>
        <year>2011</year>
        <other-data-here/>
    </incident>
    <incident>
        <year>2009</year>
        <other-data-here/>
    </incident>
    <incident>
        <year>2006</year>
    </incident>
</incidents>

想要的正确结果(从$pThisYear开始的所有年份的事件$pYearsBack年)已生成:

<incidents>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2011</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2009</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2006</year>
   </incident>
</incidents>

二. XSLT 2.0 解决方案:

与往常一样,XSLT 2.0 解决方案更简单、更短且更具可读性:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 exclude-result-prefixes="xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pYearsBack" select="6" as="xs:integer"/>
 <xsl:param name="pThisYear" select="2012" as="xs:integer"/>

 <xsl:variable name="vEarliest" select=
  "$pThisYear - $pYearsBack -1"/>

 <xsl:variable name="vYears" select="/*/*/year/xs:integer(.)"/>

 <xsl:template match="/">
  <incidents>
   <xsl:for-each select="1 to $pYearsBack +1">
    <xsl:variable name="vthisYear" as="xs:integer"
         select="$pThisYear - . +1"/>
    <incident>
      <year>
       <xsl:sequence select=
       "($vYears[. eq $vthisYear], 'missingYear')[1]"/>
      </year>
    </incident>
   </xsl:for-each>
   </incidents>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于同一个 XML 文档(如上)时,会产生相同的正确结果:

<incidents>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2011</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2009</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>missingYear</year>
   </incident>
   <incident>
      <year>2006</year>
   </incident>
</incidents>

关于xml - 根据 XSL 中的条件动态输出元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9089598/

相关文章:

xml - 用于匹配文档中除特定元素中的文本节点之外的所有文本节点的 Xpath

xml - 如何在多个文件上使用 xmlstarlet 并附加输出?

asp.net - 限制字符串中的字符数 - XSLT

Java,如何将字符串转换为数组

iphone - 如何以编程方式创建横向 UIView?

r - 在 R 中将行转换为列

python - lxml 增量 XML 序列化重复命名空间

c# - 使用 dataSet.GetXml() 获取内存

xslt - XSL 变量转小写

java - 系统找不到 XSL 引用的 DTD