Как использовать переворачивающееся окно для группировки XML элементов по содержимому? - PullRequest
0 голосов
/ 15 февраля 2020

Как группировать в зависимости от того, есть ли совпадение с [0-9] для цифр с tumbling window?

желаемым выходом:

...
<record>
    <name>joe</name>
    <data>phone1</data>
    <data>phone2</data>
</record>
...

токовый выход, не сгруппирован:

<xml>
  <record>
    <person key="$s" data="name">phone1</person>
  </record>
  <record>
    <person key="$s" data="name">phone2</person>
  </record>
  <record>
    <person key="$s" data="name">phone3sue</person>
  </record>
  <record>
    <person key="$s" data="name">cell4</person>
  </record>
  <record>
    <person key="$s" data="name">home5alice</person>
  </record>
  <record>
    <person key="$s" data="name">atrib6</person>
  </record>
  <record>
    <person key="$s" data="name">x7</person>
  </record>
  <record>
    <person key="$s" data="name">y9</person>
  </record>
  <record>
    <person key="$s" data="name">z10</person>
  </record>
</xml>

input:

<text>
  <line>people</line>
  <line>joe</line>
  <line>phone1</line>
  <line>phone2</line>
  <line>phone3</line>
  <line>sue</line>
  <line>cell4</line>
  <line>home5</line>
  <line>alice</line>
  <line>atrib6</line>
  <line>x7</line>
  <line>y9</line>
  <line>z10</line>
</text>

Понятие состоит в том, что у каждого "человека" будет имя (без цифр) и, возможно, дополнительные данные. Итак, вы хотите прочитать в каждой строке, а затем сгруппировать в зависимости от того, где находятся имена.

code:

xquery version "3.0";

<xml>
{
for tumbling window $line in db:open("foo.txt")//text()
start $s when matches($s, '[0-9]')
return   
<record>

       <person key='$s' data="name">{$line}</person>

 </record>
}
 </xml>

Глядя на вывод, «phone3sue», очевидно, выполняет некоторое сопоставление и группировку. , хотя не совсем так, как хотелось бы, потому что «phone3» должен быть в своем собственном элементе, вложенным в «joe», а не «sue». Но, тем не менее, там происходит некоторое совпадение.


из списка рассылки saxon:

В среду, 19 февраля 2020 г. в 10:31:37 AM -0800, thufir scripsit:

Я перечитал раздел о работе с окнами; у меня сложилось впечатление, что это было больше для отображения или отчета.

Работа с окнами - это то, как вы берете куски из потока данных.

То, что у вас есть, фактически является потоком линейных элементов; Вы можете идентифицировать строки «имен», но вы не знаете, как далеко они находятся / сколько данных находится между какой-либо конкретной парой имен.

Windows позволяет вам сказать «Я хочу кусок этот поток, начинающийся со строки имени и продолжающийся вплоть до (но не включая) следующей строки имени ".

Не могли бы вы уточнить, что вы подразумеваете под двумя шагами, более конкретно?

Вы пытаетесь взять какой-то ввод XML и превратить его в другой вывод XML.

Если это чистое преобразование - измените все элементы с именем FOO на element названный BAZ - XQuery не лучший выбор инструмента. Используйте XSLT, если можете. В вычислительном отношении они одинаковы, но языки имеют разные отклонения, и XSLT преобразуется более естественно.

Если вывод XML представляет собой абстракцию вашего ввода - морально какой-то отчет - он очень помогает получить абстракцию, а затем представить ее.

Итак, в вашем случае у вас есть поток, содержащий неявную связь между именами и данными. (Это поток строк; единственный способ узнать эти строки данных go с этой строкой имени - это позиция. Так неявно.) Если вы превращаете это в явное отображение между именами и данными - например, путем создания переменной карты где ключи - это содержимое строки имени (с пробелами, которые каким-то образом обрабатываются), а записи для каждого ключа - строки данных, связанные с этим именем - вы выполнили абстракцию.

Затем вы можете взять это отобразите и создайте желаемый вывод XML, что гораздо проще, чем пытаться объединить «создать новый XML» и «выполнить шаги абстракции». Последнее, что я написал, есть пример превращения карты в элементы, но в качестве шаблона это просто

map: keys ($ map)! {.} {$ map (.)}

(становится сложнее, если в записи есть узлы или последовательность, но не намного больше.)

Это делает что-то немного ближе к смыслу?

- Грейдон

_______________________________________________ список рассылки saxon-help, заархивированный в http://saxon.markmail.org/ saxon-help@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/saxon-help

Ответы [ 3 ]

1 голос
/ 20 февраля 2020

Следующая попытка использовать tumbling window, который начинается с любого line, не содержащего ASCII di git (name из person), за которым следует любая строка, содержащая хотя бы один ASCII di git (т.е. data строк):

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method 'xml';
declare option output:indent 'yes';

<xml>
{
    for tumbling window $person in text/line
    start $name next $data when matches($name, '^[^0-9]+$') and matches($data, '[0-9]')
    return
        <person>
        {
            <name>{ data($name) }</name>,
            tail($person) ! <data>{data()}</data>

        }
        </person>
}    
</xml>

https://xqueryfiddle.liberty-development.net/gWmuPs1

Выход есть

<?xml version="1.0" encoding="UTF-8"?>
<xml>
   <person>
      <name>joe</name>
      <data>phone1</data>
      <data>phone2</data>
      <data>phone3</data>
   </person>
   <person>
      <name>sue</name>
      <data>cell4</data>
      <data>home5</data>
   </person>
   <person>
      <name>alice</name>
      <data>atrib6</data>
      <data>x7</data>
      <data>y9</data>
      <data>z10</data>
   </person>
</xml>
1 голос
/ 15 февраля 2020

Если вы используете 3.0 или 3.1, тогда используйте предложение "window" выражения FLWOR. Что-то вроде

for tumbling window $w in line
    start $s when matches($s, '[a-z]')
    return <group key="$s">{$w}</group>

Не тестировалось и, вероятно, нуждается в коррекции или адаптации.

0 голосов
/ 20 февраля 2020

Это вероятно совсем близко:

thufir@dur:~/flwor/foo.txt.database$ 
thufir@dur:~/flwor/foo.txt.database$ basex dennis.xq 
<person name="joe">
  <person id="3" x="0" numerical="true">phone1</person>
  <person id="4" x="0" numerical="true">phone2</person>
  <person id="5" x="0" numerical="true">phone3</person>
</person>
<person name="sue">
  <person id="7" x="0" numerical="true">cell4</person>
  <person id="8" x="0" numerical="true">home5</person>
</person>
<person name="alice">
  <person id="10" x="0" numerical="true">atrib6</person>
  <person id="11" x="0" numerical="true">x7</person>
  <person id="12" x="0" numerical="true">y9</person>
  <person id="13" x="0" numerical="true">z10</person>
</person>thufir@dur:~/flwor/foo.txt.database$ 

код:

xquery version "3.0";

declare variable $XML := <xml>
 <person id="1" x="0" numerical="false">people</person>
 <person id="2" x="0" numerical="false">joe</person>
 <person id="3" x="0" numerical="true">phone1</person>
 <person id="4" x="0" numerical="true">phone2</person>
 <person id="5" x="0" numerical="true">phone3</person>
 <person id="6" x="0" numerical="false">sue</person>
 <person id="7" x="0" numerical="true">cell4</person>
 <person id="8" x="0" numerical="true">home5</person>
 <person id="9" x="0" numerical="false">alice</person>
 <person id="10" x="0" numerical="true">atrib6</person>
 <person id="11" x="0" numerical="true">x7</person>
 <person id="12" x="0" numerical="true">y9</person>
 <person id="13" x="0" numerical="true">z10</person>
</xml> ;

for $P in $XML/person
where $P[@numerical="true"]
let $PREV := $P/preceding-sibling::person[@numerical="false"][1]
group by $PREV
return <person name="{$PREV}" >  { $P } </person>
...