xpath - XQUERY:如何更新 HTML 文本,在标签中包含行
问题描述
我正在尝试使用有关每一行的新信息来更新 HTML 文本片段。这是一个 HTML 示例:
<div>
<span class="column1">
<a id="l1"></a>aaaaa<span type="foo">aaa</span>aa
<br id="l2"/>aaaaaaa
</span>
<span class="column2">
<br id="l3"/>aaabbbb
<br id="l4"/>bb<span>123</span>bbbbb
<br id="l5"/>bbbbbbb
<br id="l6"/>ccccccc
</span>
</div>
这是新信息:
<sections>
<section n="1" type="intro" from="1" to="3"/><!-- @from and @to are line numbers -->
<section n="2" type="main" from="3" to="5"/>
<section n="3" type="conclusion" from="6" to="6"/>
</sections>
目标是能够根据这些新信息对线条进行不同的样式设置(例如,划分为部分)。所以最终的输出应该是这样的:
<div>
<span class="column1">
<a id="l1"/></a><span class="intro">aaaaa<span type="foo">aaa</span>aa</span>
<br id="l2"/><span class="intro">aaaaaaa</span>
</span>
<span class="column2">
<br id="l3"/><span class="intro main">aaabbbb</span>
<br id="l4"/><span class="main">bb<span>123</span>bbbbb</span>
<br id="l5"/><span class="main">bbbbbbb</span>
<br id="l6"/><span class="conclusion">ccccccc</span>
</span>
</div>
这是我到目前为止的xquery:
for $section in $sections/section
for $line in $s/@from to $s/@to
let $name := $section/@type
let $br := $text//*[contains(@id, concat('l', $line))]
let $newline := <span class="{$name}">{$text//*[contains(@id, concat('l', $line))]/following-sibling::node()[following-sibling::*[contains(@id, concat('l', $line+1))]]}</span>
return
($br, $newline)
显然这是行不通的!
- 我有一条线属于两个部分的问题。例如我得到了两个
<br id="l3"/><span class="intro">...</span>
和<br id="l3"/><span class="main">...</span>
- 如果将行分组
<span>
为列的元素(或其他级别的分组),则会丢失。
我不知道如何获得所需的输出。任何帮助将不胜感激!
解决方案
这是我将评论中链接到的 XSLT 3 转换为 XQuery 3.1 的尝试:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace array = "http://www.w3.org/2005/xpath-functions/array";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method 'html';
declare option output:html-version '5';
declare variable $sections as document-node(element(sections)) external := document {
<sections>
<section n="1" type="intro" from="1" to="3"/><!-- @from and @to are line numbers -->
<section n="2" type="main" from="3" to="5"/>
<section n="3" type="conclusion" from="6" to="6"/>
</sections>
};
declare variable $classes-per-line as map(xs:integer, xs:string*) := map:merge(for $section in $sections/sections/section, $line in $section/@from to $section/@to return map { $line : $section/@type/string() }, map { 'duplicates' : 'combine' });
declare function local:apply-templates($nodes as node()*, $line as xs:integer) as node()* {
$nodes ! (typeswitch(.)
case document-node()
return document { local:apply-templates(node(), $line) }
case element()
return
if (self::*[*/@id = 'l' || $line])
then
element { node-name() } {
local:apply-templates(@*, $line),
for tumbling window $w in node()
start $s when $s/@id
return
if ($s/@id = 'l' || $line)
then ($s, <span class="{$classes-per-line($line)}">{ local:apply-templates(tail($w), $line) }</span>)
else local:apply-templates($w, $line)
}
else
element { node-name() } { local:apply-templates((@*, node()), $line) }
default
return .
)
};
document {
<html>
<head>
<title>fragement transformation</title>
</head>
<body>
{serialize($classes-per-line, map { 'method' : 'adaptive' })}
{
fold-left(sort(map:keys($classes-per-line)), ., local:apply-templates#2)
}
</body>
</html>
}
在https://xqueryfiddle.liberty-development.net/bFukv8v/3我已经用一个简单的 local:fold-left 替换了高阶 fn:fold-left,它递归调用 local:apply-templates,以允许代码使用不支持高阶函数/函数引用的 Saxon 9.8 或更高版本的 HE。
推荐阅读
- php - Wordpress do not display the latest entries widget
- pandas - 将列的值放入单元格中
- swiftui - 带有 onTapGesture 的分段选取器不响应点击
- java - How can I sort files based on date modified in Java and copy to the respective folder
- mqtt - 使用通配符订阅 MQTT 主题
- django - Django 外键集的最大计数
- verilog - Do synthesis results differ between packed and unpacked arrays in SystemVerilog?
- javascript - Converting ALMA algorithm to javascript
- python - create pygame.Color 有时会抛出 ValueError: invalid color argument
- c# - Entity Framework executing stored procedure does not return values