XSLT удалите дубликаты и выберите более высокое значение - PullRequest
0 голосов
/ 18 июня 2019

Я новичок в XSLT и ищу помощь в удалении дубликатов <EMP> из XML-документа на основе совокупного значения их детей. Из каждой группы элементов с одинаковым значением для этого должен быть выведен элемент с наибольшим значением для AIB_Position/AIB. Ниже приведен мой пример XML-документа и соответствующий желаемый результат.

<Row_entry>
<Employees>
    <Emp>
        <Emp_id>E1</Emp_id>
        <Emp_Name>Name1</Emp_Name>
        <Country>C1</Country>
        <AIB_Position>
            <AIB>1500</AIB>
        </AIB_Position>
    </Emp>
    <Emp>
        <Emp_id>E2</Emp_id>
        <Emp_Name>Name2</Emp_Name>
        <Country>C2</Country>
        <AIB_Position>
            <AIB>1700</AIB>
        </AIB_Position>
    </Emp>
    <Emp>
        <Emp_id>E2</Emp_id>
        <Emp_Name>Name2</Emp_Name>
        <Country>C2</Country>
        <AIB_Position>
            <AIB>1800</AIB>
        </AIB_Position>
    </Emp>
 </Employees>
</Row_entry>

Желаемый вывод (удалены дубликаты элементов Emp на основе объединенного значения <Emp_id>, <Emp_Name>, <Country>):

<Row_entry>
 <Employees>
    <Emp>
        <Emp_id>E1</Emp_id>
        <Emp_Name>Name1</Emp_Name>
        <Country>C1</Country>
        <AIB_Position>
            <AIB>1500</AIB>
        </AIB_Position>
    </Emp>
    <Emp>
        <Emp_id>E2</Emp_id>
        <Emp_Name>Name2</Emp_Name>
        <Country>C2</Country>
        <AIB_Position>
            <AIB>1800</AIB>
        </AIB_Position>
    </Emp>
 </Employees>
</Row_entry>

Ответы [ 2 ]

1 голос
/ 19 июня 2019

Я думаю, что вы хотите это ( напрямую, используя функцию XPath 2.0 max () ):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xsl:output indent="yes"/>

  <xsl:template match="Employees">
      <xsl:copy>
          <xsl:for-each-group select="Emp" group-by="concat(Emp_id, '+', Emp_Name, '+', Country)">
            <xsl:copy-of select="current-group()
                 [AIB_Position/AIB/number() = max(current-group()/AIB_Position/AIB/number())][1]"/>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

И если вы подозреваете, что ваш XSLT-процессор идиотичен , например, вычисление max () более одного раза, используйте это более точное направление преобразования:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xsl:output indent="yes"/>

  <xsl:template match="Employees">
      <xsl:copy>
          <xsl:for-each-group select="Emp"
           group-by="concat(Emp_id, '+', Emp_Name, '+', Country)">
            <xsl:copy-of select=
            "for $max in max(current-group()/AIB_Position/AIB/number())
              return
                current-group()[AIB_Position/AIB/number() = $max][1]"/>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
0 голосов
/ 18 июня 2019

В XSLT 2 или более поздней версии используйте for-each-group, например, в XSLT 3 с комбинированным ключом группировки, затем сортируйте каждую группу и выводите максимальное значение:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="Employees">
      <xsl:copy>
          <xsl:for-each-group select="Emp" composite="yes" group-by="Emp_id, Emp_Name, Country">
              <xsl:for-each select="current-group()">
                  <xsl:sort select="AIB_Position/AIB" order="descending"/>
                  <xsl:if test="position() = 1">
                      <xsl:copy-of select="."/>
                  </xsl:if>
              </xsl:for-each>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

С процессором XSLT 3, поддерживающимФункция высшего порядка sort, которую вы могли бы сократить, чтобы использовать код

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:output indent="yes"/>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="Employees">
        <xsl:copy>
            <xsl:for-each-group select="Emp" composite="yes" group-by="Emp_id, Emp_Name, Country">
                <xsl:sequence select="sort(current-group(), (), function($emp) { xs:integer($emp/AIB_Position/AIB) })[last()]"/>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

https://stackoverflow.com/tags/xslt-grouping/info, содержит некоторые подробности о том, как реализовать составной ключ группировки XSLT 3 в XSLT 2 путем объединения строккомпоненты ключа, если вы ограничены XSLT 2.

...