XQUERY: Как обновить текст HTML, заключив строки в теги <span> - PullRequest
1 голос
/ 21 октября 2019

Я пытаюсь обновить фрагмент текста 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)

Очевидно, что это не работает!

  1. У меня есть проблемы, когда линия принадлежит двум разделам. Например, я получаю <br id="l3"/><span class="intro">...</span> и <br id="l3"/><span class="main">...</span>
  2. , если строки были сгруппированы в <span> элементы для столбцов (или других уровней группировки), это теряется.

Я не имею понятия, как добраться до желаемого результата. Любая помощь будет принята с благодарностью!

1 Ответ

1 голос
/ 22 октября 2019

Вот моя попытка перевести 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 У меня естьзаменил более высокий порядок fn: fold-left простым local: fold-left, который рекурсивно вызывает local: apply-templates, чтобы позволить коду работать с Saxon 9.8 или более поздним HE, который не поддерживает функции / функции высшего порядкассылки.

...