复杂的xPath查询

时间:2012-07-13 19:00:32

标签: xml xslt xpath xslt-1.0

我需要编写一个非常复杂的XSLT 1.0查询。

鉴于以下XML文件,我需要一个查询来获取多个报告中的作者集。 (例如Antonio Rossi,因为他在报告1和2中都是如此)。

<reports>
  <report id="01">
    <titolo>
      I venti del Nord
    </titolo>
    <autori>
      <autore>
        Antonio Rossi
      </autore>
      <autore>
        Mario Verdi
      </autore>
    </autori>
    <versioni>
      <versione numero="1.0">
        <data>
          13-08-1980
        </data>
        <autore>
          Mario Verdi
        </autore>
        <commento>
          versione iniziale
        </commento>
      </versione>
      <versione numero="2.0">
        <data>
          14-08-1981
        </data>
        <autore>
          Antonio Rossi
        </autore>
        <commento>
          poche modifiche
        </commento>
      </versione>
    </versioni>
  </report>
  <report id="02">
    <titolo>
      Le pioggie del Nord
    </titolo>
    <autori>
      <autore>
        Antonio Rossi
      </autore>
      <autore>
        Luca Bianchi
      </autore>
    </autori>
    <versioni>
      <versione numero="1.0">
        <data>
          13-12-1991
        </data>
        <autore>
          Antonio Rossi
        </autore>
        <commento>
          versione iniziale
        </commento>
      </versione>
      <versione numero="2.0">
        <data>
          14-08-1992
        </data>
        <autore>
          Antonio Rossi
        </autore>
        <commento>
          modifiche al cap. 1
        </commento>
      </versione>
      <versione numero="3.0">
        <data>
          18-08-1992
        </data>
        <autore>
          Antonio Rossi
        </autore>
        <commento>
          Aggiunta intro.
        </commento>
      </versione>
      <versione numero="4.0">
        <data>
          13-01-1992
        </data>
        <autore>
          Luca Bianchi
        </autore>
        <commento>
          Modifiche sostanziali.
        </commento>
      </versione>
    </versioni>
  </report>
  <report id="03">
    <titolo>
      Precipitazioni nevose
    </titolo>
    <autori>
      <autore>
        Fabio Verdi
      </autore>
      <autore>
        Luca Bianchi
      </autore>
    </autori>
    <versioni>
      <versione numero="1.0">
        <data>
          11-01-1992
        </data>
        <autore>
          Fabio Verdi
        </autore>
        <commento>
          versione iniziale
        </commento>
      </versione>
      <versione numero="2.0">
        <data>
          13-01-1992
        </data>
        <autore>
          Luca Bianchi
        </autore>
        <commento>
          Aggiornato indice
        </commento>
      </versione>
    </versioni>
  </report>
</reports>

4 个答案:

答案 0 :(得分:5)

如果您可以使用XPath 2.0,则可以使用:

distinct-values(/reports/report/autori/autore[preceding::report/autori/autore = . or following::report/autori/autore = .])

使用输入XML,它将返回:

Antonio Rossi
Luca Bianchi

答案 1 :(得分:3)

即使在XPath 1.0中也是如此:

//report//autore[text()=../../following-sibling::report//autore/text()]

它还选择所有autore个节点,其中文本内容等于以下任何autore节点中的任何report节点。

或者,为了简短起见,如果真正的xml文件中没有任何麻烦,那么即使这样也应该有效:

//autore[text()=../../following-sibling::*//autore/text()]

编辑:偶然工作。请参阅以下评论。

答案 2 :(得分:3)

<强>予。这个简单的(没有for-each,没有变量)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:key name="kAuthorByVal" match="autori/autore" use="normalize-space()"/>

  <xsl:template match="/">
   <xsl:copy-of select=
    "//autori/autore
                  [generate-id()
                  =
                   generate-id(key('kAuthorByVal', normalize-space())[1])
                   ]
                  [key('kAuthorByVal', normalize-space())[2]]"/>
  </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<reports>
      <report id="01">
        <titolo>
          I venti del Nord
        </titolo>
        <autori>
          <autore>
            Antonio Rossi
          </autore>
          <autore>
            Mario Verdi
          </autore>
        </autori>
        <versioni>
          <versione numero="1.0">
            <data>
              13-08-1980
            </data>
            <autore>
              Mario Verdi
            </autore>
            <commento>
              versione iniziale
            </commento>
          </versione>
          <versione numero="2.0">
            <data>
              14-08-1981
            </data>
            <autore>
              Antonio Rossi
            </autore>
            <commento>
              poche modifiche
            </commento>
          </versione>
        </versioni>
      </report>
      <report id="02">
        <titolo>
          Le pioggie del Nord
        </titolo>
        <autori>
          <autore>
            Antonio Rossi
          </autore>
          <autore>
            Luca Bianchi
          </autore>
        </autori>
        <versioni>
          <versione numero="1.0">
            <data>
              13-12-1991
            </data>
            <autore>
              Antonio Rossi
            </autore>
            <commento>
              versione iniziale
            </commento>
          </versione>
          <versione numero="2.0">
            <data>
              14-08-1992
            </data>
            <autore>
              Antonio Rossi
            </autore>
            <commento>
              modifiche al cap. 1
            </commento>
          </versione>
          <versione numero="3.0">
            <data>
              18-08-1992
            </data>
            <autore>
              Antonio Rossi
            </autore>
            <commento>
              Aggiunta intro.
            </commento>
          </versione>
          <versione numero="4.0">
            <data>
              13-01-1992
            </data>
            <autore>
              Luca Bianchi
            </autore>
            <commento>
              Modifiche sostanziali.
            </commento>
          </versione>
        </versioni>
      </report>
      <report id="03">
        <titolo>
          Precipitazioni nevose
        </titolo>
        <autori>
          <autore>
            Fabio Verdi
          </autore>
          <autore>
            Luca Bianchi
          </autore>
        </autori>
        <versioni>
          <versione numero="1.0">
            <data>
              11-01-1992
            </data>
            <autore>
              Fabio Verdi
            </autore>
            <commento>
              versione iniziale
            </commento>
          </versione>
          <versione numero="2.0">
            <data>
              13-01-1992
            </data>
            <autore>
              Luca Bianchi
            </autore>
            <commento>
              Aggiornato indice
            </commento>
          </versione>
        </versioni>
      </report>
</reports>

会产生想要的正确结果:

<autore>
            Antonio Rossi
          </autore>
<autore>
            Luca Bianchi
          </autore>

<强>解释

  1. 一个关键的观察结果是,具有特定字符串值的autori/autorereport内不能出现多次。这大大简化了解决方案(对于更复杂的解决方案,请查看此答案的早期版本)。这个考虑基本上用于本答案中提出的所有解决方案。

  2. 我们通过其规范化的字符串值定义一个标识autori/autore的键。因此,具有不同空格但呈现相同作者的两个autori/autore被视为同一作者的实例。

  3. 使用Muenchian分组方法,我们选择所有autori/autore元素的集合,每个元素都有不同的规范化字符串值。

  4. 对于每个具有唯一规范化字符串值的选定autori/autore,我们还测试了第二个具有相同规范化字符串值的autori/autore。我们选择所有这些autori/autore元素,这个节点集正是这个问题需要选择的。


  5. <强> II。 XSLT 2.0解决方案:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
    
     <xsl:variable name="vSeq" select="//autori/autore/normalize-space()"/>
     <xsl:template match="/">
         <xsl:value-of select="$vSeq[index-of($vSeq,.)[2]]" separator="&#xA;"/>
     </xsl:template>
    </xsl:stylesheet>
    

    当在同一个XML文档(上面)上应用此转换时,会生成所需的正确结果

    Antonio Rossi
    Luca Bianchi
    

    <强>解释

    我们使用 this answer 并相应地定义$vSeq


    <强> III。单个XPath 3.0(和XQuery 3.0)表达式 - 解决方案:

    let $vSeq := //autori/autore/normalize-space()
     return
        $vSeq[index-of($vSeq,.)[2]]
    

答案 3 :(得分:2)

恭喜DevNull获得了当时发布的第一个正确答案。在他的职位发布时,不知道OP想要一个XSLT 1.0解决方案。我在下面提供一个。

以任何有效的方式在XSLT 1.0中获取不同的值需要Muenchian分组。以下是如何在XSLT 1.0中执行此操作...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />

<xsl:key name="kAuthors" match="autori/autore" use="normalize-space()" />

<xsl:template match="/">
The set of authors on multiple reports
====================================== 
<xsl:for-each select="reports/report/autori/autore[
   generate-id()=
   generate-id( key('kAuthors',normalize-space())[1])]">
  <xsl:variable name="author" select="normalize-space()" />   
  <xsl:for-each select="key('kAuthors',$author)[2]">
   <xsl:value-of select="concat($author,'&#x0A;')" /> 
  </xsl:for-each>
 </xsl:for-each>  
</xsl:template>

</xsl:stylesheet>

上面的样式表应用于OP的样本数据时,会生成此文本文档......

The set of authors on multiple reports
====================================== 
Antonio Rossi
Luca Bianchi

说明

在每份报告中,作者出现了两次。一旦进入autori,再次在版本下。我们不需要对每个报告重复计算,因此我们为密钥autori / autore创建匹配模式。键值是作者的字符串名称。因此关键组作者。

我们使用标准的Muenchian分组来迭代作者。这是每个人的外在。现在我们只对“重犯”感兴趣。我们可以通过在内循环中应用[2]谓词来实现这一点。仅出现在最多1个报告中的作者将被过滤掉,因为他们的小组长度仅为1。