2010-02-17 54 views
2

我正在将XML转换为HTML。在XML的一部分中,我需要计算在比较特定后代时看起来“相同”的元素,而其他后代和任何属性必须被忽略。XSLT基于子孙子集计数“相同”元素

下面是我的XML的简化示例。真实情况要复杂得多,我刚刚删除了不相关的计数元素:

<complaints> 
    <lodgedComplaint> 
     <defendant>First Person</defendant> 
     <charge> 
      <actionNumber>1</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA1</legislation> 
        <description>Stealing</description> 
       </offenceSection> 
       <placeOfOffence>Sydney</placeOfOffence> 
       <dateOfOffence>2010-01-01</dateOfOffence> 
       <particular>value=20</particular> 
      </offence> 
     </charge> 
     <charge> 
      <actionNumber>2</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA2</legislation> 
        <description>Theft</description> 
       </offenceSection> 
       <placeOfOffence>Sydney</placeOfOffence> 
       <dateOfOffence>2010-01-01</dateOfOffence> 
      </offence> 
     </charge> 
     <charge> 
      <actionNumber>3</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA2</legislation> 
        <description>Theft</description> 
       </offenceSection> 
       <placeOfOffence>London</placeOfOffence> 
       <dateOfOffence>2010-01-01</dateOfOffence> 
      </offence> 
     </charge> 
     <charge> 
      <actionNumber>4</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA1</legislation> 
        <description>Stealing</description> 
       </offenceSection> 
       <placeOfOffence>Sydney</placeOfOffence> 
       <dateOfOffence>2010-01-01</dateOfOffence> 
       <particular>value=50</particular> 
      </offence> 
     </charge> 
     <charge> 
      <actionNumber>5</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA2</legislation> 
        <description>Theft</description> 
       </offenceSection> 
       <placeOfOffence>Sydney</placeOfOffence> 
       <dateOfOffence>2010-01-02</dateOfOffence> 
      </offence> 
     </charge> 
    </lodgedComplaint> 
    <lodgedComplaint> 
     <defendant>Second Person</defendant> 
     <charge> 
      <actionNumber>1</actionNumber> 
      <offence> 
       <offenceSection> 
        <legislation>SA1</legislation> 
        <description>Stealing</description> 
       </offenceSection> 
       <placeOfOffence>Sydney</placeOfOffence> 
       <dateOfOffence>2010-01-01</dateOfOffence> 
       <particular>value=35</particular> 
      </offence> 
     </charge> 
    </lodgedComplaint> 
</complaints>

在每个lodgedComplaint,任何两个收费应被视为相同的,如果它们的立法说明,placeOfOffence和dateOfOffence元素匹配。 actionNumber和特定的元素必须被忽略(特定的元素是可选的,在我已经给出的模式中是无界的)。

所需的输出应该是这个样子:

First Person 
    2 counts of Stealing at Sydney on 1/1/2010 under SA1 
    1 count of Theft at Sydney on 1/1/2010 under SA2 
    1 count of Theft at London on 1/1/2010 under SA2 
    1 count of Theft at Sydney on 2/1/2010 under SA2 
Second Person 
    1 count of Stealing at Sydney on 1/1/2010 under SA1

下面是一个XSLT我试过了,根据事情我已经在堆栈溢出或其他地方阅读。它不起作用;费用细节完全不显示。我认为我使用concat()会导致问题。 我该怎么做?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" encoding="UTF-8" indent="yes"/> 
    <xsl:key name="matchOffence" match="offence" use="concat(offenceSection/legislation,offenceSection/description,placeOfOffence,dateOfOffence)"/> 
    <xsl:template match="/"> 
     <html> 
      <head> 
       <title>CRIMES Listings</title> 
       <link rel="stylesheet" type="text/css" href="global_styles.css"/> 
       <link rel="stylesheet" type="text/css" href="styles.css"/> 
      </head> 
      <body> 
       <xsl:apply-templates select="complaints/lodgedComplaint"/> 
      </body> 
     </html> 
    </xsl:template> 

    <xsl:template match="lodgedComplaint"> 
     <br/> 
     <xsl:value-of select="defendant"/> 
     <xsl:for-each select="charge/offence[generate-id(concat(offenceSection/legislation,offenceSection/description,placeOfOffence,dateOfOffence))=generate-id(key('matchOffence',.))]"> 
      <br/> 
      <xsl:value-of select="count(../../charge/offence[(offenceSection/legislation=current()/offenceSection/legislation) and (offenceSection/description=current()/offenceSection/description) and (placeOfOffence=current()/placeOfOffence) and (dateOfOffence=current()/dateOfOffence)])"/> 
      counts of <b><xsl:value-of select="offenceSection/description"/></b> 
      at <b><xsl:value-of select="placeOfOffence"/></b> 
      on <b><xsl:call-template name="date"> 
       <xsl:with-param name="text" select="dateOfOffence"/> 
      </xsl:call-template></b> 
      under <b><xsl:value-of select="offenceSection/legislation"/></b> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template name="date"> 
     <xsl:param name="text" select="."/> 
     <xsl:choose> 
      <xsl:when test="contains($text,'-')"> 
       <xsl:call-template name="date"> 
        <xsl:with-param name="text" select="substring-after($text,'-')"/> 
       </xsl:call-template>/<xsl:value-of select="substring-before($text,'-')"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet>

回答

1

样式表有两个问题。

  1. 您正在使用concat(),其产生的字符串结果的结果,试图generate-id()generate-id()只适用于节点。

    应该重新写为:<xsl:for-each select="charge/offence[generate-id(.)=generate-id(key('matchOffence',concat(offenceSection/legislation,./offenceSection/description,placeOfOffence,dateOfOffence)))]">

  2. 的另一个问题是,用于key字符串值不是唯一的。第二人的offence与第一人的offense具有相同的值。这会阻止您为第二个人生成输出。通过在密钥中添加defendant元素的值,可以使key更加独特。

    调整key后,那么你显然需要调整for-each

在你的样式全部放在一起:

<?xml version="1.0" encoding="UTF-8"?>  
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" encoding="UTF-8" indent="yes"/> 
    <xsl:key name="matchOffence" match="offence" use="concat(../../defendant,offenceSection/legislation,offenceSection/description,placeOfOffence,dateOfOffence)"/> 
    <xsl:template match="/"> 
     <html> 
      <head> 
       <title>CRIMES Listings</title> 
       <link rel="stylesheet" type="text/css" href="global_styles.css"/> 
       <link rel="stylesheet" type="text/css" href="styles.css"/> 
      </head> 
      <body> 
       <xsl:apply-templates select="complaints/lodgedComplaint"/> 
      </body> 
     </html> 
    </xsl:template> 

    <xsl:template match="lodgedComplaint"> 
     <br/> 
     <xsl:value-of select="defendant"/> 
     <xsl:for-each select="charge/offence[generate-id(.)=generate-id(key('matchOffence',concat(../../defendant,offenceSection/legislation,./offenceSection/description,placeOfOffence,dateOfOffence)))]"> 

      <br/> 
      <xsl:value-of select="count(../../charge/offence[(offenceSection/legislation=current()/offenceSection/legislation) and (offenceSection/description=current()/offenceSection/description) and (placeOfOffence=current()/placeOfOffence) and (dateOfOffence=current()/dateOfOffence)])"/> 
      counts of <b><xsl:value-of select="offenceSection/description"/></b> 
      at <b><xsl:value-of select="placeOfOffence"/></b> 
      on <b><xsl:call-template name="date"> 
       <xsl:with-param name="text" select="dateOfOffence"/> 
      </xsl:call-template></b> 
      under <b><xsl:value-of select="offenceSection/legislation"/></b> 

     </xsl:for-each> 
    </xsl:template> 

    <xsl:template name="date"> 
     <xsl:param name="text" select="."/> 
     <xsl:choose> 
      <xsl:when test="contains($text,'-')"> 
       <xsl:call-template name="date"> 
        <xsl:with-param name="text" select="substring-after($text,'-')"/> 
       </xsl:call-template>/<xsl:value-of select="substring-before($text,'-')"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 
+0

谢谢 - 完美的作品。 –