You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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 := "&#10;";  
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 := "&#10;";

(: 提取所有章节的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 14:32:41