Удалить дубликаты элементов на основе атрибутов и значений - PullRequest
0 голосов
/ 02 июня 2018

Есть много вопросов о том, как удалить дубликаты элементов, когда вы можете сгруппировать эти элементы по определенному атрибуту или значению, однако в моем случае атрибуты динамически генерируются в XSLT, и я неНе нужно программировать каждый атрибут для каждого элемента, который будет использоваться в качестве ключа группировки.

Как удалить дублирующиеся элементы, не зная заранее их атрибутов?До сих пор я пытался использовать generate-id() для каждого элемента и группировать по ним, но проблема в том, что generate-id не генерирует одинаковый идентификатор для элементов с одинаковыми атрибутами:

<xsl:template match="root">
    <xsl:variable name="tempIds">
        <xsl:for-each select="./*>
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:attribute name="tempID">
                    <xsl:value-of select="generate-id(.)"/>
                </xsl:attribute>
                <xsl:copy-of select="node()"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:variable>
    <xsl:for-each-group select="$tempIds" group-by="@tempID">
        <xsl:sequence select="."/>
    </xsl:for-each-group>
</xsl:template>

Testданные:

<root>
    <child1>
        <etc/>
    </child1>
    <dynamicElement1 a="2" b="3"/>
    <dynamicElement2 c="3" d="4"/>
    <dynamicElement2 c="3" d="5"/>
    <dynamicElement1 a="2" b="3"/>
</root>

Конечным результатом является только один из двух оставшихся dynamicElement1 элементов:

<root>
    <child1>
        <etc/>
    </child1>
    <dynamicElement1 a="2" b="3"/>
    <dynamicElement2 c="3" d="4"/>
    <dynamicElement2 c="3" d="5"/>
</root>

Ответы [ 2 ]

0 голосов
/ 22 июня 2018
<xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="root/*[@a= following-sibling::*/@a]|root/*[@c= following-sibling::*/@c and @d= following-sibling::*/@d]"/>
You may try this
0 голосов
/ 02 июня 2018

В XSLT 3, как показано в https://xsltfiddle.liberty -development.net / pPqsHTi , вы можете использовать составной ключ всех атрибутов, например,

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

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

  <xsl:output indent="yes"/>

  <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="*" composite="yes" group-by="@*">
              <xsl:sequence select="."/>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Обратите внимание, что технически атрибуты не являютсяупорядочено таким образом, что было бы безопаснее группировать по виду атрибутов по node-name () или аналогичным, как это было сделано с XSLT 3 без функций высшего порядка в https://xsltfiddle.liberty -development.net / pPqsHTi / 2

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:mf="http://example.com/mf"
    version="3.0">

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

  <xsl:output indent="yes"/>

  <xsl:function name="mf:node-sort" as="node()*">
      <xsl:param name="input-nodes" as="node()*"/>
      <xsl:perform-sort select="$input-nodes">
          <xsl:sort select="namespace-uri()"/>
          <xsl:sort select="local-name()"/>
      </xsl:perform-sort>
  </xsl:function>

  <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="*" composite="yes" group-by="mf:node-sort(@*)">
              <xsl:sequence select="."/>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

или как вы могли бы сделать с Saxon EE просто с помощью

<xsl:template match="root">
    <xsl:copy>
        <xsl:for-each-group select="*" composite="yes" group-by="sort(@*, (), function($att) { namespace-uri($att), local-name($att) })">
            <xsl:sequence select="."/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>
...