在 zsh 或 bash 中使用 XMLStarlet 解析 XML 的速度效率
Speed efficiency in parsing XML with XMLStarlet in zsh or bash
我们有一个相当复杂的 zsh 应用程序,它使用 XML 文件来存储其配置和数据。当前读取和写入这些文件的方法是使用 xmlstarlet.
当更新一个文件时,我们将整个 XML 多次通过管道传输,对于我们接触的每个属性或元素一次,如下所示:
cat "$config" \
| xml_addSubnode "/a/b/c" "foo" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr1" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr2" "wwww" \
\
| xml_addSubnode "/a/b/c/foo[last()]" "attr3" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr4" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr5" "kkkk" \
\
| xml_update "$config"
每次分别调用xml
将属性读入shell个变量:
local foo="$(xml_value "$xpath" "$config")"
local bar="$(xml_value "$xpath" "$config")"
...
效用函数归结如下:
xml_addSubnode() {
...
cat | xml ed -s "$elementXPath" -t elem -n "$element"
}
xml_createOrUpdateAttribute()
{
...
cat | xml ed --update ... --insert ...
}
xml_value()
{
...
xml sel -t -v "$xPath" "$xmlFile"
}
xml_update()
{
...
cat > "$file"
}
此代码在功能上运行良好,但显然性能很糟糕。
如何使这段代码更有效率?还有哪些其他方法可以使用 zsh 或 bash 解析 XML 以产生更快的执行速度?
使用另一种格式也是一种选择,尽管这需要一些迁移工作。我知道 jq
JSON 解析器,但用法与 xmlstarlet
类似,如果我采用相同的方法,我不会有太多收获,对吧?
程序在FreeBSD上运行。
您可以使用 xmlstarlet
一次性完成所有更新,这比调用它 6 次要快得多:
#!/usr/bin/env zsh
cat test.xml
print -- --------
xmlstarlet ed \
-s '/a/b/c' -t elem -n foo \
-s '/a/b/c/foo[last()]' -t attr -n attr1 -v zzzz \
-s '/a/b/c/foo[last()]' -t attr -n attr2 -v wwww \
-s '/a/b/c/foo[last()]' -t elem -n bar \
-s '/a/b/c/foo[last()]/bar' -t attr -n attr3 -v zzzz \
-s '/a/b/c/foo[last()]/bar' -t attr -n attr4 -v kkkk \
test.xml
示例:
$ ./test.sh
<?xml version="1.0"?>
<a><b><c/></b></a>
--------
<?xml version="1.0"?>
<a>
<b>
<c>
<foo attr1="zzzz" attr2="wwww">
<bar attr3="zzzz" attr4="kkkk"/>
</foo>
</c>
</b>
</a>
我们有一个相当复杂的 zsh 应用程序,它使用 XML 文件来存储其配置和数据。当前读取和写入这些文件的方法是使用 xmlstarlet.
当更新一个文件时,我们将整个 XML 多次通过管道传输,对于我们接触的每个属性或元素一次,如下所示:
cat "$config" \
| xml_addSubnode "/a/b/c" "foo" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr1" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]" "attr2" "wwww" \
\
| xml_addSubnode "/a/b/c/foo[last()]" "attr3" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr4" "zzzz" \
| xml_createOrUpdateAttribute "/a/b/c/foo[last()]/bar" "attr5" "kkkk" \
\
| xml_update "$config"
每次分别调用xml
将属性读入shell个变量:
local foo="$(xml_value "$xpath" "$config")"
local bar="$(xml_value "$xpath" "$config")"
...
效用函数归结如下:
xml_addSubnode() {
...
cat | xml ed -s "$elementXPath" -t elem -n "$element"
}
xml_createOrUpdateAttribute()
{
...
cat | xml ed --update ... --insert ...
}
xml_value()
{
...
xml sel -t -v "$xPath" "$xmlFile"
}
xml_update()
{
...
cat > "$file"
}
此代码在功能上运行良好,但显然性能很糟糕。
如何使这段代码更有效率?还有哪些其他方法可以使用 zsh 或 bash 解析 XML 以产生更快的执行速度?
使用另一种格式也是一种选择,尽管这需要一些迁移工作。我知道 jq
JSON 解析器,但用法与 xmlstarlet
类似,如果我采用相同的方法,我不会有太多收获,对吧?
程序在FreeBSD上运行。
您可以使用 xmlstarlet
一次性完成所有更新,这比调用它 6 次要快得多:
#!/usr/bin/env zsh
cat test.xml
print -- --------
xmlstarlet ed \
-s '/a/b/c' -t elem -n foo \
-s '/a/b/c/foo[last()]' -t attr -n attr1 -v zzzz \
-s '/a/b/c/foo[last()]' -t attr -n attr2 -v wwww \
-s '/a/b/c/foo[last()]' -t elem -n bar \
-s '/a/b/c/foo[last()]/bar' -t attr -n attr3 -v zzzz \
-s '/a/b/c/foo[last()]/bar' -t attr -n attr4 -v kkkk \
test.xml
示例:
$ ./test.sh
<?xml version="1.0"?>
<a><b><c/></b></a>
--------
<?xml version="1.0"?>
<a>
<b>
<c>
<foo attr1="zzzz" attr2="wwww">
<bar attr3="zzzz" attr4="kkkk"/>
</foo>
</c>
</b>
</a>