如何用XQuery 3.1生成人物共现列表并统计共现章节数?
解决XML人物共现分析的XQuery优化方案
需求说明
处理包含<person>标签的书籍XML文件,用XQuery 3.1计算同一章节内的人物共现关系,生成符合网络分析需求的CSV边数据——输出去重的单向人物对及共现章节总数。
简化XML示例
<book> <chapter n="I"> <person>Susan</person> <person>Victor</person> </chapter> <chapter n="II"> <person>Victor</person> <person>Susan</person> <person>Victor</person> <person>Iago</person> <person>Victor</person> </chapter> <chapter n="III"> <person>Susan</person> <person>Iago</person> <person>Scott</person> <person>Susan</person> </chapter> </book>
目标CSV输出
From,To,Chapters Susan,Victor,2 Susan,Iago,2 Victor,Iago,1 Susan,Scott,1
原代码问题
原代码存在两个核心问题:
- 生成双向重复人物对(如同时出现
Susan,Victor和Victor,Susan) - 每个共现章节单独成行,未按人物对汇总共现章节数
原代码:
declare option saxon:output "method=text"; declare variable $linefeed := " "; concat('From,To,Chapters', $linefeed, string-join( let $persons := //person/string()=>distinct-values() for $person in $persons let $pers-chapters := //chapter[.//person/string()=$person] for $pers-chapter in $pers-chapters let $chap-num := $pers-chapter/data(@n) let $fellow-occupants := $pers-chapter//person/string()=>distinct-values() for $fellow-occupant in $fellow-occupants where $fellow-occupant!=($person) return concat ($person,',', $fellow-occupant, ',', $chap-num), $linefeed))
优化后的XQuery代码
declare option saxon:output "method=text"; declare variable $linefeed := " "; (: 提取所有章节的ID和去重人物列表 :) let $chapters := //chapter ! map { 'id': data(@n), 'persons': .//person/string() => distinct-values() } (: 生成章节内的单向人物对(避免A-B和B-A重复) :) let $all-pairs := $chapters ! ( let $pers-list := ?persons for $i in 1 to count($pers-list) - 1 for $j in $i + 1 to count($pers-list) return map { 'from': $pers-list[$i], 'to': $pers-list[$j], 'chapter': ?id } ) (: 按人物对分组,统计共现章节数 :) let grouped-pairs := $all-pairs => group-by( function($pair) { concat($pair?from, "|", $pair?to) } ) let result-rows := map:keys(grouped-pairs) ! ( let $pair := grouped-pairs(.)[1] let $co-occur-count := count(grouped-pairs(.)) return concat($pair?from, ",", $pair?to, ",", $co-occur-count) ) (: 拼接表头和结果输出 :) return concat('From,To,Chapters', $linefeed, string-join(result-rows, $linefeed))
核心改进点
- 消除重复人物对:通过索引
$i < $j的方式,仅生成人物列表中位置靠前到靠后的单向对,彻底避免双向重复。 - 汇总共现章节数:先收集所有有效人物对及其所在章节,再通过
group-by按人物对分组,分组后的数量即为共现章节总数。 - 提升处理效率:一次性提取所有章节的人物列表,避免原代码中多次重复遍历XML节点的冗余操作。
内容的提问来源于stack exchange,提问作者haggis78
相关产品推荐
相关产品推荐

