如何基于子节点合并/分组XML文档

时间:2019-06-05 11:20:06

标签: xml xslt xquery

我想知道如何通过内容对XML元素进行合并/分组/组合,以使分组的值仅出现一次,并将其余节点合并到结果中,就像在现代SQL语句中将结果分组一样MariaDB(结果中没有重复项)。

我已经在寻找解决方案,但是此处或其他地方给出的示例与我的要求不符-调整后也没有。 我猜想<lemma>的位置可能是个问题。另一方面,我认为/希望以某种方式仍然可以找到解决方案。

我的文档的简化结构和所需的输出:

XML:

<root>
  <artikel>
    <lemma-position>
      <lemma>Abend</lemma>
      <info>aaa</info>
    </lemma-position>
    <bedeutungsposition nr="1a">
      <bedeutung>Zeit am Ende des Tages</bedeutung>
    </bedeutungsposition>
    <bedeutungsposition nr="1b">
      <bedeutung>
        was anderes
      </bedeutung>
    </bedeutungsposition>
  </artikel>
  <artikel>
    <lemma-position>
      <lemma>Abend</lemma>
      <info>bbb</info>
    </lemma-position>
    <bedeutungsposition nr="1">
      <bedeutung>abcdefg</bedeutung>
    </bedeutungsposition>
    <bedeutungsposition nr="2">
      <bedeutung>japoisdfoiasjdfoasjdfl</bedeutung>
    </bedeutungsposition>
  </artikel>
</root>

在此示例中,节点<lemma>包含“ Abend”,这应该是分组的值。

所需的输出:

<root>
  <artikel>
    <lemma-position>
      <lemma>Abend</lemma>
      <info>aaa</info>
      <info>bbb</lemma>
    </lemma-position>
    <bedeutungsposition nr="1">
      <bedeutung>abcdefg</bedeutung>
    </bedeutungsposition>
    <bedeutungsposition nr="1a">
      <bedeutung>Zeit am Ende des Tages</bedeutung>
    </bedeutungsposition>
    <bedeutungsposition nr="1b">
      <bedeutung>
        was anderes
      </bedeutung>
    </bedeutungsposition>
    <bedeutungsposition nr="2">
      <bedeutung>japoisdfoiasjdfoasjdfl</bedeutung>
    </bedeutungsposition>
  </artikel>
</root>

我得到的是一个未合并的副本,即XML输入或它的一部分,但根本没有合并。到目前为止,我已经尝试了几种方法,其中的基础总是像这样:

<xsl:template match="/">
  <xsl:copy>
    <xsl:for-each-group select="artikel" group-by="//lemma">
      <xsl:copy-of select="current-group()//lemma/*" />
      <!--
        I also placed some other paths and expressions here or above to 
        select the elements differently, without success however.  
      -->
    </xsl:for-each-group>

  </xsl:copy>
</xsl:template>

我也尝试过使用distinct-values等进行xQuery,但是它也不起作用(没有重复项)。

我正在用Oxygen和baseX进行测试,它们都连接到Saxon-9.8 HE,所以实际上应该没问题。 XSLT中的一种解决方案与xQuery中的一种解决方案一样值得赞赏

1 个答案:

答案 0 :(得分:3)

我认为主要模板是

  <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="artikel" group-by="lemma-position/lemma">
              <xsl:copy>
                  <lemma-position>
                      <lemma>
                          <xsl:value-of select="current-grouping-key()"/>
                      </lemma>
                      <xsl:apply-templates select="current-group()/lemma-position/(* except lemma)"/>
                  </lemma-position>
                  <xsl:apply-templates select="current-group()/(* except lemma-position)">
                      <xsl:sort select="@nr"/>
                  </xsl:apply-templates>
              </xsl:copy>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

与身份转换(例如,在xsl:mode on-no-match="shallow-copy"声明的XSLT 3中)一起获得https://xsltfiddle.liberty-development.net/gWvjQfR

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="#all"
    version="3.0">

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

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="artikel" group-by="lemma-position/lemma">
              <xsl:copy>
                  <lemma-position>
                      <lemma>
                          <xsl:value-of select="current-grouping-key()"/>
                      </lemma>
                      <xsl:apply-templates select="current-group()/lemma-position/(* except lemma)"/>
                  </lemma-position>
                  <xsl:apply-templates select="current-group()/(* except lemma-position)">
                      <xsl:sort select="@nr"/>
                  </xsl:apply-templates>
              </xsl:copy>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

您可以在BaseX XQuery中使用

<root>
{
    for $artikel in root/artikel
    group by $lemma := $artikel/lemma-position/lemma
    return
        <artikel>
           <lemma-position>
             <lemma>{$lemma}</lemma>
             {
                 $artikel/lemma-position/(* except lemma)
             }
           </lemma-position>
           {
               sort($artikel/(* except lemma-position), (), function($el) { $el/@nr })
           }
        </artikel>
}
</root>