我有一个包含作者和编辑者的XML文件。
<?xml version="1.0" encoding="UTF-8"?>
<?oxygen RNGSchema="file:textbook.rnc" type="compact"?>
<books xmlns="books">
<book ISBN="i0321165810" publishername="OReilly">
<title>XPath</title>
<author>
<name>
<fname>Priscilla</fname>
<lname>Walmsley</lname>
</name>
</author>
<year>2007</year>
<field>Databases</field>
</book>
<book ISBN="i0321165812" publishername="OReilly">
<title>XQuery</title>
<author>
<name>
<fname>Priscilla</fname>
<lname>Walmsley</lname>
</name>
</author>
<editor>
<name>
<fname>Lisa</fname>
<lname>Williams</lname>
</name>
</editor>
<year>2003</year>
<field>Databases</field>
</book>
<publisher publishername="OReilly">
<web-site>www.oreilly.com</web-site>
<address>
<street_address>hill park</street_address>
<zip>90210</zip>
<state>california</state>
</address>
<phone>400400400</phone>
<e-mail>oreilly@oreilly.com</e-mail>
<contact>
<field>Databases</field>
<name>
<fname>Anna</fname>
<lname>Smith</lname>
</name>
</contact>
</publisher>
</books>
我正在寻找一种方法来返回作为作者和/或编辑被列出次数最多的人。解决方案应该是XQuery 1.0(XPath 2.0)兼容。
我正在考虑使用FLWOR查询迭代所有作者和编辑,然后计算唯一的作者/编辑,然后返回匹配最高计数的作者/编辑。但我找不到合适的解决方案。
有没有人对如何编写这样的FLWOR查询有任何建议? 可以使用XPath以更简单的方式完成吗?
致以最诚挚的问候,
珍
答案 0 :(得分:15)
这可能有所帮助:
declare default element namespace 'books';
(for $name in distinct-values($doc/books/*/*/name)
let $entries := $doc/books/*[data(*/name) = $name]
order by count($entries) descending
return $entries/*/name)[1]
答案 1 :(得分:7)
这是一个纯粹的XPath 2.0表达式,诚然不适合胆小的人:
(for $m in max(for $n in distinct-values(/*/b:book/(b:author | b:editor)
/b:name/concat(b:fname, '|', b:lname)),
$cnt in count(/*/b:book/(b:author | b:editor)
/b:name[$n eq concat(b:fname, '|', b:lname) ])
return $cnt
),
$name in /*/b:book/(b:author | b:editor)/b:name,
$fullName in $name/concat(b:fname, '|', b:lname),
$count in count( /*/b:book/(b:author | b:editor)
/b:name[$fullName eq concat(b:fname, '|', b:lname)])
return
if($count eq $m)
then $name
else ()
)[1]
其中前缀"b:"
与名称空间"books"
相关联。
基于XSLT 2.0的验证:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="books">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:sequence select=
"(for $m in max(for $n in distinct-values(/*/b:book/(b:author | b:editor)
/b:name/concat(b:fname, '|', b:lname)),
$cnt in count(/*/b:book/(b:author | b:editor)
/b:name[$n eq concat(b:fname, '|', b:lname) ])
return $cnt
),
$name in /*/b:book/(b:author | b:editor)/b:name,
$fullName in $name/concat(b:fname, '|', b:lname),
$count in count( /*/b:book/(b:author | b:editor)
/b:name[$fullName eq concat(b:fname, '|', b:lname)])
return
if($count eq $m)
then $name
else ()
)[1]
"/>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档:
<books xmlns="books">
<book ISBN="i0321165810" publishername="OReilly">
<title>XPath</title>
<author>
<name>
<fname>Priscilla</fname>
<lname>Walmsley</lname>
</name>
</author>
<year>2007</year>
<field>Databases</field>
</book>
<book ISBN="i0321165812" publishername="OReilly">
<title>XQuery</title>
<author>
<name>
<fname>Priscilla</fname>
<lname>Walmsley</lname>
</name>
</author>
<editor>
<name>
<fname>Lisa</fname>
<lname>Williams</lname>
</name>
</editor>
<year>2003</year>
<field>Databases</field>
</book>
<publisher publishername="OReilly">
<web-site>www.oreilly.com</web-site>
<address>
<street_address>hill park</street_address>
<zip>90210</zip>
<state>california</state>
</address>
<phone>400400400</phone>
<e-mail>oreilly@oreilly.com</e-mail>
<contact>
<field>Databases</field>
<name>
<fname>Anna</fname>
<lname>Smith</lname>
</name>
</contact>
</publisher>
</books>
选择了正确的name
元素并输出:
<name xmlns="books">
<fname>Priscilla</fname>
<lname>Walmsley</lname>
</name>
答案 2 :(得分:4)
我一直认为这是XPath中的遗漏:max()和min()函数返回最高/最低值,而你通常想要的是集合中具有最高/最高值的对象某些表达式的最低值。一种解决方案是对该值上的对象进行排序,并从列表中取出第一个/最后一个,这似乎是不优雅的。计算最小值/最大值然后选择其值与此匹配的项目似乎同样没有吸引力。在Saxon中,长期存在一对高阶扩展函数saxon:highest()和saxon:lowest(),它接受一个序列和一个函数,并返回具有最低或最高值的序列中的项目。功能结果。好消息是,在XPath 3.0中,您可以自己编写这些函数(实际上,它们是作为示例中的用户编写的函数示例)。
答案 3 :(得分:2)
你走在正确的轨道上。最简单的方法是将名称转换为字符串(例如,用空格分隔)并使用这些:(注意以下代码未经测试)
let $names := (//editor | //author)/concat(fname, ' ', lname)
let $distinct-names := distinct-values($names)
let $name-count := for $name in $distinct-names return count($names[. = $name])
for $name at $pos in $distinct-names
where $name-count[$pos] = max($name-count)
return $name
或者,另一种方法:
(
let $people := (//editor | //author)
for $person in $people
order by count($people[fname = $person/fname and
lname = $person/lname])
return $person
)[last()]