Xml 复杂xPath查询
我需要编写一个相当复杂的XSLT1.0查询 给定以下XML文件,我需要一个查询来获取多个报表中的作者集。(例如安东尼奥·罗西,因为他同时出现在报告1和报告2中)Xml 复杂xPath查询,xml,xslt,xpath,xslt-1.0,Xml,Xslt,Xpath,Xslt 1.0,我需要编写一个相当复杂的XSLT1.0查询 给定以下XML文件,我需要一个查询来获取多个报表中的作者集。(例如安东尼奥·罗西,因为他同时出现在报告1和报告2中) 我是凡蒂德尔诺德酒店 安东尼奥·罗西 马里奥·威尔第 13-08-1980 马里奥·威尔第 版本化 14-08-1981 安东尼奥·罗西 波切修正 北皮奥吉酒店 安东尼奥·罗西 卢卡·比安奇 13-12-1991 安东尼奥·罗西 版本化 14-08-1992 安东尼奥·罗西 改良铝盖。1. 18-08-1992 安东尼奥·罗西 Agg
我是凡蒂德尔诺德酒店
安东尼奥·罗西
马里奥·威尔第
13-08-1980
马里奥·威尔第
版本化
14-08-1981
安东尼奥·罗西
波切修正
北皮奥吉酒店
安东尼奥·罗西
卢卡·比安奇
13-12-1991
安东尼奥·罗西
版本化
14-08-1992
安东尼奥·罗西
改良铝盖。1.
18-08-1992
安东尼奥·罗西
Aggiunta简介。
13-01-1992
卢卡·比安奇
修改sostanziali。
沉淀性痣
法比奥·威尔第
卢卡·比安奇
11-01-1992
法比奥·威尔第
版本化
13-01-1992
卢卡·比安奇
印度阿吉奥罗纳托酒店
如果可以使用XPath 2.0,则可以使用:
distinct-values(/reports/report/autori/autore[preceding::report/autori/autore = . or following::report/autori/autore = .])
输入XML后,它将返回:
Antonio Rossi
Luca Bianchi
即使在XPath 1.0中也可以这样做:
//report//autore[text()=../../following-sibling::report//autore/text()]
它还选择所有autore
节点,这些节点的文本内容与以下任何report
节点中的任何autore
节点相同
或者,简而言之,如果真正的xml文件中没有什么真正棘手的问题,那么即使这样也应该可以:
//autore[text()=../../following-sibling::*//autore/text()]
编辑:意外工作。请参阅下面的评论。祝贺DevNull获得了当时发布的第一个正确答案。在他发表文章时,不知道OP想要XSLT1.0解决方案。我在下面提供一个 在XSLT1.0中以任何有效的方式获取不同的值都需要Muenchian分组。下面是如何在XSLT1.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>
解释
在每份报告中,作者出现两次。一次在autori下,另一次在VersionOne下。我们不需要对每个报告重复计数,因此我们为键autori/autore创建匹配模式。键值是作为字符串的作者姓名。因此,关键群体的作者
我们使用标准的Muenchian分组对作者进行迭代。这是每个人的外皮。现在我们只对“惯犯”感兴趣。我们可以通过对内部循环应用[2]谓词来实现这一点。最多只出现在一个报告中的作者将被过滤掉,因为他们的组长度只有1个。I.这个简单的(每个都没有,没有变量)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>
<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>
<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>
Antonio Rossi
Luca Bianchi
let $vSeq := //autori/autore/normalize-space()
return
$vSeq[index-of($vSeq,.)[2]]
将此转换应用于同一XML文档(如上)时,将生成所需的正确结果:
<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>
<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>
<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>
Antonio Rossi
Luca Bianchi
let $vSeq := //autori/autore/normalize-space()
return
$vSeq[index-of($vSeq,.)[2]]
说明:
<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>
<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>
<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>
Antonio Rossi
Luca Bianchi
let $vSeq := //autori/autore/normalize-space()
return
$vSeq[index-of($vSeq,.)[2]]
这里我们使用并相应地定义$vSeq
III.单个XPath 3.0(和XQuery 3.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>
<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>
<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>
Antonio Rossi
Luca Bianchi
let $vSeq := //autori/autore/normalize-space()
return
$vSeq[index-of($vSeq,.)[2]]
这两种解决方案都是错误的,原因有很多。文本节点的第一个直接比较是错误的,因为autore的文本子级显然包含一定数量的非重要空白,用于视觉呈现。您需要使用normalise-space()防止出现这种情况。这也是错误的,因为它没有生成一个明确的列表。如果一位作者出现在3份报告中,他将被列入两次名单,这与OP对“一组作者”的规定相反。更多关于下一条评论……考虑到问题的措辞,返回一系列文本节点而不是元素会更准确。最后,它的效率非常低。第一个表达式的成本将与文档的大小成正比,而不是立方。@SeanB.Durkin您实际上是非常正确的。
/text()
和normalize-space()
问题很容易解决(现在我可以看到我在处理示例输入时是多么幸运),但是名称多次出现的问题是一个真正的问题,我认为仅使用XPath 1.0无法解决(或者是吗?),我认为XPath 1.0实际上无法解决。其他用户的其他解决方案实际上都使用XSLT或XPath2.0。回答得很好。这个答案值得一提。尽管在比较中最好使用normalize-space()。@SeanB.Durkin:包含的内容正好相反——XQuery 3.0是XPath 3.0的超集(完全包含)。