【发布时间】:2018-04-24 09:03:38
【问题描述】:
这是一个效率问题,而不是故障排除问题。我有以下代码sn-p:
# The -R flag restores malformed XML
xmlstarlet -q fo -R <<<"$xml_content" | \
# Delete xml_data
xmlstarlet ed -d "$xml_data" | \
# Delete index
xmlstarlet ed -d "$xml_index" | \
# Delete specific objects
xmlstarlet ed -d "$xml_nodes/objects" | \
# Append new node
xmlstarlet ed -s "$xml_nodes" -t elem -n subnode -v "Hello World" | \
# Add x attribute to node
xmlstarlet ed -i "($xml_nodes)[last()]" -t attr -n x -v "0" | \
# Add y attribute to node
xmlstarlet ed -i "($xml_nodes)[last()]" -t attr -n y -v "0" | \
# Add z attribute to node
xmlstarlet ed -i "($xml_nodes)[last()]" -t attr -n z -v "1" \
> "$output_file"
变量
$xml_content包含内容的xml树和
使用cat命令从大小为 472.6 MB 的文件中解析出的节点。变量
$output_file顾名思义,包含路径 到输出文件。- 其余变量仅包含我要编辑的相应 XPath。
根据帮助提出此代码的简短article,它表明:
这有点低效,因为 xml 文件被解析和写入两次。
在我的例子中,它被解析和写入两次以上(最终在 loop 中超过 1000 次)。
因此,以上述脚本为例,该短片段的执行时间仅是 4 分 7 秒。
假设过多、重复且可能效率低下的管道以及文件大小是代码运行缓慢的原因,我最终插入/删除的子节点越多最终会导致它执行得更慢。
如果我通过重申自己或提出一个旧的且可能已经回答的主题可能听起来单调,我提前道歉,但是,我真的很想了解 xmlstarlet 如何详细处理大型 XML 文档。
更新
正如@Cyrus 在他之前的回答中所说:
这两个 xmlstarlets 应该可以完成这项工作:
xmlstarlet -q fo -R <<<"$xml_content" |\ xmlstarlet ed \ -d "$xml_data" \ -d "$xml_index" \ -d "$xml_nodes/objects" \ -s "$xml_nodes" -t elem -n subnode -v "Hello World" \ -i "($xml_nodes)[last()]" -t attr -n x -v "0" \ -i "($xml_nodes)[last()]" -t attr -n y -v "0" \ -i "($xml_nodes)[last()]" -t attr -n z -v "1" > "$output_file"
这产生了以下错误:
-:691.84: Attribute x redefined-:691.84: Attribute z redefined-:495981.9: xmlSAX2Characters: huge text node: out of memory-:495981.9: Extra content at the end of the document
老实说,我不知道这些错误是如何产生的,因为我经常更改代码以测试各种场景和潜在的替代方案,但是,这就是我的诀窍:
xmlstarlet ed --omit-decl -L \
-d "$xml_data" \
-d "$xml_index" \
-d "$xml_nodes/objects" \
-s "$xml_nodes" -t elem -n subnode -v "Hello World" \
"$temp_xml_file"
xmlstarlet ed --omit-decl -L \
-i "($xml_nodes)[last()]" -t attr -n x -v "0" \
-i "($xml_nodes)[last()]" -t attr -n y -v "0" \
-i "($xml_nodes)[last()]" -t attr -n z -v "1" \
"$temp_xml_file"
关于插入的实际data,这是我一开始的:
...
<node>
<subnode>A</subnode>
<subnode>B</subnode>
<objects>1</objects>
<objects>2</objects>
<objects>3</objects>
...
</node>
...
执行上面的(拆分)代码给了我想要的:
...
<node>
<subnode>A</subnode>
<subnode>B</subnode>
<subnode x="0" y="0" z="1">Hello World</subnode>
</node>
...
通过拆分它们,xmlstarlet 能够将attributes 插入到新创建的节点中,否则它将在--subnode 甚至创建之前将它们添加到所选Xpath 的last() 实例中。在某种程度上,这仍然是低效的,不过,现在代码运行不到一分钟。
以下代码,
xmlstarlet ed --omit-decl -L \
-d "$xml_data" \
-d "$xml_index" \
-d "$xml_nodes/objects" \
-s "$xml_nodes" -t elem -n subnode -v "Hello World" \
-i "($xml_nodes)[last()]" -t attr -n x -v "0" \
-i "($xml_nodes)[last()]" -t attr -n y -v "0" \
-i "($xml_nodes)[last()]" -t attr -n z -v "1" \
"$temp_xml_file"
但是,给我这个:
...
<node>
<subnode>A</subnode>
<subnode x="0" y="0" z="1">B</subnode>
<subnode>Hello World</subnode>
</node>
...
通过将xmlstarlets 加入到post 中也由@Cyrus 回答的类似中,它以某种方式首先添加attributes,然后创建--subnode,其中innerText 是Hello World。
- 谁能解释为什么会发生这种奇怪的行为?
这是另一个reference,它声明“每个编辑操作都是按顺序执行的”
上面的文章准确地解释了我正在寻找的东西,但我无法设法使其在一个 xmlstarlet ed \ 中全部工作。或者,我试过了:
- 将
($xml_nodes)[last()]替换为$xml_nodes[text() = 'Hello World'] - 使用
$prev(或$xstar:prev)作为-i的参数,就像在这个answer 中一样。 [Examples] -
temporary element name 技巧通过
-r在添加attr后重命名临时节点
以上所有内容都插入--subnode,但新元素不带attributes。
注意:我在 OS X El Capitan v 10.11.3 上运行 XMLStarlet 1.6.1
奖金
正如我在开头提到的那样,我希望使用 loop 类似的东西:
list="$(tr -d '\r' < $names)"
for name in $list; do
xmlstarlet ed --omit-decl -L \
-d "$xml_data" \
-d "$xml_index" \
-d "$xml_nodes/objects" \
-s "$xml_nodes" -t elem -n subnode -v "$name" \
-i "($xml_nodes)[last()]" -t attr -n x -v "0" \
-i "($xml_nodes)[last()]" -t attr -n y -v "0" \
-i "($xml_nodes)[last()]" -t attr -n z -v "1" \
"$temp_xml_file"
done
$list 包含一千多个不同的名称,需要添加它们各自的attributes。每个属性的--value 也可能因每个loop 而不同。鉴于上述模型:
如果属性已正确添加到相应的节点,那么
loop的最快和最准确的版本是什么?在外部 txt 文件中创建节点列表,然后将这些 xml 元素(在 txt 文件中)添加到另一个 XML 文件中会更快吗?如果是,如何?也许是
sed或grep?
关于最后一个问题,我指的是this。应该添加来自 txt 的 xml 的节点必须是特定的,例如至少可以通过 XPath 选择,因为我只想编辑某些节点。
注意:上面的模型只是一个例子。实际的loop 将为每个loop 添加26 个--subnodes,为每个--subnode 添加3 或4 个attr。这就是为什么 xmlstarlet 正确添加 attr 而不是其他元素很重要的原因。它们必须按顺序添加。
【问题讨论】:
-
我用示例输入/输出更新了我的问题,就像你建议的@Cyrus
标签: xml bash shell unix xmlstarlet