我需要编写一个非常复杂的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>
答案 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>
<强>解释强>:
一个关键的观察结果是,具有特定字符串值的autori/autore
在report
内不能出现多次。这大大简化了解决方案(对于更复杂的解决方案,请查看此答案的早期版本)。这个考虑基本上用于本答案中提出的所有解决方案。
我们通过其规范化的字符串值定义一个标识autori/autore
的键。因此,具有不同空格但呈现相同作者的两个autori/autore
被视为同一作者的实例。
使用Muenchian分组方法,我们选择所有autori/autore
元素的集合,每个元素都有不同的规范化字符串值。
对于每个具有唯一规范化字符串值的选定autori/autore
,我们还测试了第二个具有相同规范化字符串值的autori/autore
。我们选择所有这些autori/autore
元素,这个节点集正是这个问题需要选择的。
<强> 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="
"/>
</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,'
')" />
</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。