找到所有子元素的最大值,并在xslt中获取它的父元素

时间:2010-08-11 21:54:23

标签: xml xslt xpath

此问题与此帖Find maximum value of all child elements and get its parent element in XSLT有关。我错误地问了我的问题。实际上我需要的输出有点不同。我需要将站点节点ID与工作站点节点匹配,并找出为该站点工作更长时间的人员。

<root>
    <Site id="S1">
        <othernodes></othernodes>
    </Site>
    <Site id="S2">
        <othernodes></othernodes>
    </Site>
    <Site id="S3">
        <othernodes></othernodes>
    </Site> 
    <WorkSite Person="P1" Site="S1">
        <Hours>8</Hours>
    </WorkSite>
    <WorkSite Person="P1" Site="S2">
        <Hours>2</Hours>
    </WorkSite>
    <WorkSite Person="P1" Site="S3">
        <Hours>20</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S1">
        <Hours>6</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S2">
        <Hours>10</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S3">
        <Hours>21</Hours>
    </WorkSite>
</root>

转换后的内容应该是这样的

<root>
    <site id="S1">
            <othernodes></othernodes>
            <person>P1</person>
    </site>
    <site id="S2">
            <othernodes></othernodes>
            <person>P2</person>
    </site>
    <site id="S3">
            <othernodes></othernodes>
            <person>P1</person>
    </site>
</root>

有人可以为此提供帮助吗?

4 个答案:

答案 0 :(得分:1)

这样的东西?

<xsl:template match="/">
  <root>
    <xsl:apply-templates select="root/Site" />
  </root>
</xsl:template>

<xsl:template match="/root/Site">
  <xsl:variable name="sid" select="./@id" />
  <site id="{./@id}">
    <othernodes></othernodes>
    <xsl:apply-templates select="/root/WorkSite[@Site = $sid]">
      <xsl:sort select="./Hours" data-type="number" order="descending"/>
    </xsl:apply-templates>
  </site>
</xsl:template>

<xsl:template match="/root/WorkSite">
  <xsl:if test="position() = 1">
    <person><xsl:value-of select="./@Person" /></person>
  </xsl:if>
</xsl:template>

答案 1 :(得分:1)

此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:key name="kSiteByName" match="@Site" use="."/>

 <xsl:key name="kWorksiteBySite"
   match="WorkSite" use="@Site"/>

 <xsl:key name="kSiteChildrenBySiteid"
  match="Site/node()" use="../@id"/>

 <xsl:variable name="vSites" select=
  "/*/*/@Site[generate-id()
             =
              generate-id(key('kSiteByName',.)[1])
              ]"
  />

 <xsl:template match="/">
  <root>
    <xsl:for-each select="$vSites">
      <xsl:for-each select="key('kWorksiteBySite', .)">
        <xsl:sort select="Hours" data-type="number"
         order="descending"/>
        <xsl:if test="position()=1">
         <site id="{@Site}">
            <xsl:copy-of select="key('kSiteChildrenBySiteid', @Site)"/>
            <person><xsl:value-of select="@Person"/></person>
         </site>
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
  </root>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<root>
    <Site id="S1">
        <othernodes></othernodes>
    </Site>
    <Site id="S2">
        <othernodes></othernodes>
    </Site>
    <Site id="S3">
        <othernodes></othernodes>
    </Site>
    <WorkSite Person="P1" Site="S1">
        <Hours>8</Hours>
    </WorkSite>
    <WorkSite Person="P1" Site="S2">
        <Hours>2</Hours>
    </WorkSite>
    <WorkSite Person="P1" Site="S3">
        <Hours>20</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S1">
        <Hours>6</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S2">
        <Hours>10</Hours>
    </WorkSite>
    <WorkSite Person="P2" Site="S3">
        <Hours>21</Hours>
    </WorkSite>
</root>

生成想要的正确结果

<root>
   <site id="S1">
      <othernodes/>
      <person>P1</person>
   </site>
   <site id="S2">
      <othernodes/>
      <person>P2</person>
   </site>
   <site id="S3">
      <othernodes/>
      <person>P2</person>
   </site>
</root>

请注意

  1. 使用Muenchian方法进行分组以查找所有不同的内容 网站价值。

  2. 通过按降序排序找到最大值的方式,并从排序的节点列表中获取第一个结果。 效率更高(O(N * log(N))比多次扫描节点序列(将每个值与值列表中的每个值进行比较),其具有O(N ^ N ^ 2)时间复杂度。

答案 2 :(得分:0)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="BySite" match="WorkSite" use="@Site"/>
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Site/*[last()]">
        <xsl:call-template name="identity"/>
        <person>
            <xsl:value-of select="substring-after(
                                    key('BySite',../@id)
                                      [not(key('BySite',@Site)/Hours
                                           > Hours)]
                                      /@Person,
                                    'P')" />
        </person>
    </xsl:template>
    <xsl:template match="WorkSite"/>
</xsl:stylesheet>

输出:

<root>
    <Site id="S1">
        <othernodes></othernodes>
        <person>1</person>
    </Site>
    <Site id="S2">
        <othernodes></othernodes>
        <person>2</person>
    </Site>
    <Site id="S3">
        <othernodes></othernodes>
        <person>2</person>
    </Site>
</root>

答案 3 :(得分:0)

这就是我要做的。 (我添加了for-each,以防您在一个网站上有多个完全相同的小时数。)

编辑:在我添加答案之前,我没有看到其他帖子中的XSLT 1.0要求。对此感到抱歉!

XML输入:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <Site id="S1">
    <othernodes/>
  </Site>
  <Site id="S2">
    <othernodes/>
  </Site>
  <Site id="S3">
    <othernodes/>
  </Site>
  <WorkSite Person="P1" Site="S1">
    <Hours>8</Hours>
  </WorkSite>
  <WorkSite Person="P1" Site="S2">
    <Hours>2</Hours>
  </WorkSite>
  <WorkSite Person="P1" Site="S3">
    <Hours>20</Hours>
  </WorkSite>
  <WorkSite Person="P2" Site="S1">
    <Hours>6</Hours>
  </WorkSite>
  <WorkSite Person="P2" Site="S2">
    <Hours>10</Hours>
  </WorkSite>
  <WorkSite Person="P2" Site="S3">
    <Hours>21</Hours>
  </WorkSite>
</root>

XSLT 2.0样式表:

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

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Site">
    <xsl:variable name="vSiteId">
      <xsl:value-of select="@id"/>
    </xsl:variable>
    <xsl:variable name="vMaxHours">
      <xsl:value-of select="max(/root/WorkSite[@Site=$vSiteId]/Hours)"/>
    </xsl:variable>
    <site id="{@id}">
      <xsl:apply-templates/>
      <xsl:for-each select="/root/WorkSite[Hours=$vMaxHours]/@Person">
        <person>
          <xsl:value-of select="."/>
        </person>        
      </xsl:for-each>
    </site>
  </xsl:template>

  <xsl:template match="WorkSite"/>

</xsl:stylesheet>

XML输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <site id="S1">
      <othernodes/>
      <person>P1</person>
   </site>
   <site id="S2">
      <othernodes/>
      <person>P2</person>
   </site>
   <site id="S3">
      <othernodes/>
      <person>P2</person>
   </site>
</root>