Как работать со встроенным html в xml с помощью jq yq xq (преобразование xml в yaml)
У меня есть файл словаря xml, основанный на формате словаря xdxf , который я хотел бы преобразовать (и туда и обратно) в yaml.
Этот формат (с DTD) может содержать элементы (перекрестные ссылки) вокруг слова, которое уже окружено<deftext>
теги (определения). Или он может содержать, например, теги для обозначения слова в нижнем индексе. Мне не удалось увидеть, как управлять преобразованием этих файлов из xml в yaml с версией yq (либо для go, либо для python).
Сокращенный образец файла sample.xml (из репозитория xdxf)
<lexicon>
<ar>
<k id="fb982hk">Society</k>
<def>
<deftext>Plural form of word <kref>index</kref>.
</deftext>
</def>
</ar>
<ar>
<k>CO
<sub>2</sub>
</k>
<def>
<deftext>Carbon dioxide (CO<sub>2</sub>) - a heavy odorless gas formed during respiration.
</deftext>
</def>
</ar>
</lexicon>
преобразованный в yaml через yq (go), будет отображаться:
yq -p=xml -o=yaml < sample.xml
lexicon:
ar:
- k:
+content: Society
+@id: fb982hk
def:
deftext:
+content:
- Plural form of word
- .
kref: index
- k:
+content: CO
sub: "2"
def:
deftext:
+content:
- Carbon dioxide (CO
- ) - a heavy odorless gas formed during respiration.
sub: "2"
преобразованный в yaml через yq (python), будет отображаться:
xq < sample.xml | yq -y
lexicon:
ar:
- k:
'@id': fb982hk
'#text': Society
def:
deftext:
kref: index
'#text': Plural form of word .
- k:
sub: '2'
'#text': CO
def:
deftext:
sub: '2'
'#text': Carbon dioxide (CO) - a heavy odorless gas formed during respiration.
В обоих случаях<kref>
и<sub>
элементы больше не будут «окружать» правильный текст, и возврат к xml также будет неправильным. Это просто ограничение формата? Или есть способ разместить (или, может быть, игнорировать как xml?) эти теги?
2 ответа
Синтаксис XML не является проблемой.
Вы боретесь с (общим) способом, которым mikefarah/yq и kislyuk/yq выбрали для представления дерева XML в JSON/YAML. Для этого не существует канонического решения, и оба этих подхода являются потерями по отношению к «сложным типам со смешанным содержимым», т. е. узлам элементов, встроенным в плавающие текстовые узлы.
Но изменение синтаксиса XML может быть решением.
Если вас не волнует информация разметки, передаваемая рассматриваемыми элементами, вы можете сгладить эти отрывки на этапе предварительной обработки, например, используя простое преобразование XSL, например
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="kref|sub">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Здесь используется сопоставление с шаблономnode()|@*
который просто копирует все элементы и атрибуты, а другой переопределяет это поведение дляkref
иsub
элементы, копируя только их текстовое содержимое.
Примените этот XSLT к своему XML-документу с помощью XSLT-процессора, такого какxsltproc
,Saxon
, илиXalan
, и вы должны получить урезанную версию вашего ввода:
<lexicon>
<ar>
<k id="fb982hk">Society</k>
<def>
<deftext>
Plural form of word index.
</deftext>
</def>
</ar>
<ar>
<k>CO2</k>
<def>
<deftext>
Carbon dioxide (CO2) - a heavy odorless gas formed during respiration.
</deftext>
</def>
</ar>
</lexicon>
Затем это можно применить к исходномуxq
/yq
трубопровод.
Если вам нужно быстрое и немного хакерское решение и если вы хотите сохранить специфичную для HTML «разметку», вы можете сделать хуже, чем:
sed -E -e 's/<(kref|sub)>/!\1>/g' -e 's,</(kref|sub)>,!/\1>,g' |
yq -p=xml -o=yaml |
sed -E -e 's/!(kref|sub)>/<\1>/g' -e 's,!/(kref|sub)>,</\1>,g'
Вашему sed может потребоваться другой вариант обработки регулярных выражений. Или вы можете использовать какой-либо другой инструмент для изменения текста, например jq:
jq -Rr 'gsub("<(?<tag>kref|sub)>"; "!\(.tag)>") | gsub("</(?<tag>kref|sub)>"; "!\(.tag)>")' |
yq -p=xml -o=yaml |
jq -Rr 'gsub("!(?<tag>kref|sub)>"; "<\(.tag)>") | gsub("!/(<tag>kref|sub)>"; "</\(.tag)>")'