Используйте xmlstarlet для преобразования XML, содержащего повторяющиеся и отсутствующие поля, в разделенные табуляцией - PullRequest
0 голосов
/ 08 мая 2020

У меня есть большой сложный XML файл, содержащий шаблон, подобный следующему

<?xml version="1.0" encoding="UTF-8"?>
<records>
  <record>
    <field1>field1</field1>
    <field2>field2</field2>
    <field2>field2</field2>
    <field3>field3</field3>
    <field4>field4</field4>
    <field4>field4</field4>
  </record>
  <record>
    <field1>field1</field1>
    <field1>field1</field1>
    <field3>field3</field3>
    <field4>field4</field4>
    <field4>field4</field4>
  </record>
</records>

Я хотел бы использовать xmlstarlet, чтобы преобразовать его в разделитель табуляции с повторяющимися полями, разделенными точкой с запятой, например

field1\tfield2;field2\tfield3\tfield4;field4
field1;field1\t\tfield3\t\field4;field4

Я могу делать то, что мне нужно, сворачивая повторяющиеся поля с помощью процедуры обработки строк перед загрузкой файла в xmlstarlet, но это кажется хакерским. Есть ли элегантный способ сделать все это в xmlstarlet?

1 Ответ

0 голосов
/ 08 мая 2020

Вы можете использовать следующую команду :

xmlstarlet sel -t -m "/records/record" -m "*[starts-with(local-name(),field)]" -i "position()=1" -v "." --else -i "local-name() = local-name(preceding-sibling::*[1])" -v "concat(';',.)" --else -v "concat('\t',.)" -b -b -b -n input.xml

В псевдокоде это выглядит примерно так:

  • For-each /records/record
  • Для каждого имени элемента, которое начинается с field
  • Если это первый элемент, выведите элемент
  • Else
  • Если проверьте, если текущее имя элемента совпадает с предыдущим
  • Затем вывод ;Item
  • Другой вывод \tItem
  • b действительно означает «разрыв» из l oop или предложение if
  • n выводит новую строку

Его вывод:

field1\tfield2;field2\tfield3\tfield4;field4
field1;field1\tfield3\tfield4;field4

Приведенный выше код различается на основе имен элементов. Если вместо этого вы хотите дифференцировать на основе значений элементов, используйте следующую команду:

xmlstarlet sel -t -m "/records/record" -m "*[starts-with(local-name(),field)]" -i "position()=1" -v "." --else -i ". = preceding-sibling::*[1]" -v "concat(';',.)" --else -v "concat('\t',.)" -b -b -b -n a.xml

В вашем примере XML результат такой же (поскольку имена полей и значения полей идентичны).

...