如何使用jq yq xq (xml到yaml转换)处理xml中嵌入的html



我有一个基于xdxf字典格式的xml字典文件,我想将它转换(和往返)为yaml。

这种格式(带有DTD)可以在已经被<deftext>标记(定义)包围的单词周围包含<kref>(交叉引用)元素。或者它可能包含例如<sub>标记来指示下标中的单词。我还没有能够看到如何管理xml到yaml转换这些文件与yq(无论是go或python)版本。

一个简短的sample.xml(来自xdxf repo)

<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>
通过yq (go)将

转换为yaml将呈现:

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"
通过yq (python)将

转换为yaml将呈现:

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?)这些标记?

XML语法不是问题。

你正在与mikefarah/yq和kislyuk/yq选择在JSON/YAML中表示XML树的(一般)方式作斗争。没有规范的解决方案,这两种方法对于"混合内容的复杂类型"来说都是有损的,即元素节点嵌入到浮动的文本节点中。

但是修改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()|@*的模板,它只是复制了所有的元素和属性,另一个模板通过复制krefsub元素的文本内容来覆盖这些行为。

使用XSLT处理器(如xsltprocSaxonXalan)将此XSLT应用于XML文档,您应该得到输入的剥离版本:

<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)>")'

最新更新