Найти максимальное значение всех дочерних элементов и получить его родительский элемент в xslt - PullRequest
2 голосов
/ 12 августа 2010

Этот вопрос относится к этому сообщению Найдите максимальное значение всех дочерних элементов и получите его родительский элемент в XSLT .Я задал свой вопрос неправильно.На самом деле мне нужен выход немного другой.Мне нужно сопоставить идентификатор узла сайта с узлом рабочего места и найти человека, который работал на этом сайте больше часов.

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

1 голос
/ 12 августа 2010

Это преобразование 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. Использование метода Мюнхена для группировки для поиска всех различных значений Site.

  2. Максимум пути определяется путем сортировки по убыванию и получения первого результата из отсортированного списка узлов. Это намного эффективнее (O (N * log (N)), чем сканирование последовательности узлов несколько раз (сравнение каждого значения с каждым значением в списке значений), которое имеет O (N ^ 2) сложность времени.

1 голос
/ 12 августа 2010

Как то так?

<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>
0 голосов
/ 12 августа 2010

Я бы так и сделал.(Я добавил 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>
0 голосов
/ 12 августа 2010

Эта таблица стилей:

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...