与 xmlstarlet 一起使用的 XML/XPath 表达式是什么,用于将元素移动到第一个元素?
What is the XML/XPath expression to use with xmlstarlet to move an element to be the first element?
我有一个 XML 文件类似于:
<?xml version="1.0"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Folder>
<name>Assets and Risks</name>
<Placemark>
<name>Asset_4000</name>
<description>Address: 2286</description>
<Point>
<coordinates>xxx.xxx,yyy.yyy,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Risk_2000</name>
<description>Address: 32</description>
<Point>
<coordinates>xxx.xxx,yyy.yyy,0</coordinates>
</Point>
</Placemark>
</Folder>
<Folder>
<name>The second folder</name>
</Folder>
</Document>
</kml>
我想使用 xmlstarlet(最好是所有命令行而不是 XSLT)将 Risk_2000 的地标移动到同一文件夹中的第一个地标(即 Asset_4000 的地标之前) ).
我知道第一部分是:
xmlstarlet edit --move "//_:kml/_:Document/_:Folder[_:name=\"Assets and Risks\"]/_:Placemark[_:name=\"Risk_2000\"]" **But What Goes Here**
感谢任何指导。
以下解决方案有效 - 但是,由于 xmlstarlet 的 --move
的工作方式,而不是移动“Risk_2000 的地标成为同一文件夹中的第一个地标",您必须将当前的第一个地标移动到第一个 Folder
元素的底部。您还必须声明默认名称空间。
所以尝试:
xml edit -N x="http://www.opengis.net/kml/2.2" \
--move "//x:Placemark[.//.='Asset_4000']" "//x:Folder[1]" file.xml
输出(给定上面的 xml)应该是您的预期输出。
xmlstarlet edit
的 --move
的目的地必须是单个节点,
所以变通:
- 在位置N插入临时元素
- 从源元素更新它
- 删除源元素
- 重命名临时元素
(对于 non-GNU/Linux 平台调整引用和行继续
以下命令中的字符。)
xmlstarlet edit -N v='http://www.opengis.net/kml/2.2' \
--insert '//v:Folder[v:name="Assets and Risks"]/v:Placemark[1]' \
--type elem --name 'Placemark_TMP' --value '' \
--update '$xstar:prev' --expr '../v:Placemark[v:name="Risk_2000"]/node()' \
--delete '$xstar:prev/../v:Placemark[v:name="Risk_2000"]' \
--rename '$xstar:prev' --value 'Placemark' \
file.xml | xmlstarlet format --nsclean
xmlstarlet edit
代码可以使用方便的 $xstar:prev
(又名
$prev
) 节点引用最近创建的节点
-i / --insert
、-a / --append
或 -s / --subnode
选项。例子
$xstar:prev
中给出了
doc/xmlstarlet.txt 和
源代码的 examples/ed-backref*.
--expr '../v:Placemark[…]/node()'
深度复制元素的
子节点但不是其属性
(background)。
有问题的元素没有属性,否则使用 XPath
--expr '../v:Placemark[…]/node() | ../v:Placemark[…]/@*'
.
--nsclean
步骤删除了冗余的命名空间声明。
因为 xmlstarlet
支持 exslt 可能有
set:leading 或
set:trailing
功能,但我没有研究它。
对于基于样式表的方法,请参见
.
更新 2021-09-29
上面的代码可以使用
改写如下
- 简短命令和选项
--var <name> <xpath>
选项(在
doc/xmlstarlet.txt
但不在用户指南中)
- 默认命名空间shortcut
_:
并添加 | $src/@*
以包含属性:
xmlstarlet ed \
--var dir '//_:Folder[_:name="Assets and Risks"]' \
--var tgt '$dir/_:Placemark[1]' \
--var src '$dir/_:Placemark[_:name="Risk_2000"]' \
-i '$tgt' -t elem -n 'Placemark_TMP' -v '' \
-u '$xstar:prev' -x '$src/node() | $src/@*' \
-d '$src' \
-r '$xstar:prev' -v 'Placemark' \
file.xml | xmlstarlet fo -N
根据建议 exslt 函数 set:leading
和 set:trailing
可能是相关的,或者可能不值得,但是当
printf '%s\n' '<doc><c><nm>C2</nm><e1/><e2/><e3/><e4/></c></doc>' |
xmlstarlet ed -O --pf --var T '/doc/c[nm="C2"]' -u '$T' -x 'set:trailing($T/*, e2)'
产出
<doc><c><e1/><e2/><e3/><e4/><e3/><e4/></c></doc>
我会暂缓考虑:<nm>C2</nm>
可能已经走了
但我有预感它坐在
src/xml_edit.c。
然而,从那里取下来是另一回事。
我有一个 XML 文件类似于:
<?xml version="1.0"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Folder>
<name>Assets and Risks</name>
<Placemark>
<name>Asset_4000</name>
<description>Address: 2286</description>
<Point>
<coordinates>xxx.xxx,yyy.yyy,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Risk_2000</name>
<description>Address: 32</description>
<Point>
<coordinates>xxx.xxx,yyy.yyy,0</coordinates>
</Point>
</Placemark>
</Folder>
<Folder>
<name>The second folder</name>
</Folder>
</Document>
</kml>
我想使用 xmlstarlet(最好是所有命令行而不是 XSLT)将 Risk_2000 的地标移动到同一文件夹中的第一个地标(即 Asset_4000 的地标之前) ).
我知道第一部分是:
xmlstarlet edit --move "//_:kml/_:Document/_:Folder[_:name=\"Assets and Risks\"]/_:Placemark[_:name=\"Risk_2000\"]" **But What Goes Here**
感谢任何指导。
以下解决方案有效 - 但是,由于 xmlstarlet 的 --move
的工作方式,而不是移动“Risk_2000 的地标成为同一文件夹中的第一个地标",您必须将当前的第一个地标移动到第一个 Folder
元素的底部。您还必须声明默认名称空间。
所以尝试:
xml edit -N x="http://www.opengis.net/kml/2.2" \
--move "//x:Placemark[.//.='Asset_4000']" "//x:Folder[1]" file.xml
输出(给定上面的 xml)应该是您的预期输出。
xmlstarlet edit
的 --move
的目的地必须是单个节点,
所以变通:
- 在位置N插入临时元素
- 从源元素更新它
- 删除源元素
- 重命名临时元素
(对于 non-GNU/Linux 平台调整引用和行继续 以下命令中的字符。)
xmlstarlet edit -N v='http://www.opengis.net/kml/2.2' \
--insert '//v:Folder[v:name="Assets and Risks"]/v:Placemark[1]' \
--type elem --name 'Placemark_TMP' --value '' \
--update '$xstar:prev' --expr '../v:Placemark[v:name="Risk_2000"]/node()' \
--delete '$xstar:prev/../v:Placemark[v:name="Risk_2000"]' \
--rename '$xstar:prev' --value 'Placemark' \
file.xml | xmlstarlet format --nsclean
xmlstarlet edit
代码可以使用方便的 $xstar:prev
(又名
$prev
) 节点引用最近创建的节点
-i / --insert
、-a / --append
或 -s / --subnode
选项。例子
$xstar:prev
中给出了
doc/xmlstarlet.txt 和
源代码的 examples/ed-backref*.
--expr '../v:Placemark[…]/node()'
深度复制元素的
子节点但不是其属性
(background)。
有问题的元素没有属性,否则使用 XPath
--expr '../v:Placemark[…]/node() | ../v:Placemark[…]/@*'
.
--nsclean
步骤删除了冗余的命名空间声明。
因为 xmlstarlet
支持 exslt 可能有
set:leading 或
set:trailing
功能,但我没有研究它。
对于基于样式表的方法,请参见
更新 2021-09-29
上面的代码可以使用
改写如下- 简短命令和选项
--var <name> <xpath>
选项(在 doc/xmlstarlet.txt 但不在用户指南中)- 默认命名空间shortcut
_:
并添加 | $src/@*
以包含属性:
xmlstarlet ed \
--var dir '//_:Folder[_:name="Assets and Risks"]' \
--var tgt '$dir/_:Placemark[1]' \
--var src '$dir/_:Placemark[_:name="Risk_2000"]' \
-i '$tgt' -t elem -n 'Placemark_TMP' -v '' \
-u '$xstar:prev' -x '$src/node() | $src/@*' \
-d '$src' \
-r '$xstar:prev' -v 'Placemark' \
file.xml | xmlstarlet fo -N
根据建议 exslt 函数 set:leading
和 set:trailing
可能是相关的,或者可能不值得,但是当
printf '%s\n' '<doc><c><nm>C2</nm><e1/><e2/><e3/><e4/></c></doc>' |
xmlstarlet ed -O --pf --var T '/doc/c[nm="C2"]' -u '$T' -x 'set:trailing($T/*, e2)'
产出
<doc><c><e1/><e2/><e3/><e4/><e3/><e4/></c></doc>
我会暂缓考虑:<nm>C2</nm>
可能已经走了
但我有预感它坐在
src/xml_edit.c。
然而,从那里取下来是另一回事。