xml 如何使用 xmlstarlet 在另一个元素下插入一个新元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5954168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to insert a new element under another with xmlstarlet?
提问by simpatico
$ vim test.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
</config>
$ xmlstarlet ed -i "/config" -t elem -n "sub" -v "" test.xml
<?xml version="1.0" encoding="UTF-8"?>
<sub></sub>
<config>
</config>
But I wanted sub to be a child of config. How should I change the xpath parameter of -i?
但我希望 sub 成为 config 的孩子。我应该如何更改-i的xpath 参数?
BONUS: Is it possible to insert the child directly with an attribute and even have it set to a value? Something like:
奖励:是否可以直接使用属性插入子项,甚至将其设置为值?就像是:
$ xmlstarlet ed -i "/config" -t elem -n "sub" -v "" -a attr -n "class" -v "com.foo" test.xml
采纳答案by npostavs
Use -s(or --subnode) instead of -i. Regarding the bonus, you can't insert an element with an attribute directly but since every edit operation is performed in sequence, to insert an element and then add an attribute:
使用-s(或--subnode)代替-i。关于奖励,您不能直接插入带有属性的元素,但是由于每个编辑操作都是按顺序执行的,因此插入一个元素然后添加一个属性:
> xml ed -s /config -t elem -n sub -v "" -i /config/sub -t attr -n class -v com.foo test.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<sub class="com.foo"></sub></config>
回答by cellux
I had a similar problem: I had a Tomcat configuration file (server.xml), and had to insert a <Resource>tag with pre-defined attributes into the <GlobalNamingResources>section.
我有一个类似的问题:我有一个 Tomcat 配置文件 (server.xml),并且必须在<Resource>该<GlobalNamingResources>部分中插入一个带有预定义属性的标签。
Here is how it looked before:
这是它之前的样子:
<GlobalNamingResources>
<!-- Editable user database that can also be used
by UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase"
auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
Here is what I wanted to achieve:
这是我想要实现的目标:
<GlobalNamingResources>
<!-- Editable user database that can also be used
by UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase"
auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
<Resource name="jdbc/templateassets"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://DBHOST:DBPORT/DBNAME?createDatabaseIfNotExist=false&useUnicode=true&characterEncoding=utf-8"
username="DBUSER"
password="DBPASS"
maxActive="150"
maxIdle="10"
initialSize="10"
validationQuery="SELECT 1"
testOnBorrow="true" />
</GlobalNamingResources>
Here is how I did it (snippet from a shell script):
这是我是如何做到的(来自 shell 脚本的片段):
if [ -n "$(xmlstarlet sel -T -t -v "/Server/GlobalNamingResources/Resource[@name='jdbc/templateassets']/@name" server.xml)" ]; then
echo "Resource jdbc/templateassets already defined in server.xml"
else
echo "Adding resource jdbc/templateassets to <GlobalNamingResources> in server.xml"
xmlstarlet ed -P -S -L -s /Server/GlobalNamingResources -t elem -n ResourceTMP -v "" \
-i //ResourceTMP -t attr -n "name" -v "jdbc/templateassets" \
-i //ResourceTMP -t attr -n "auth" -v "Container" \
-i //ResourceTMP -t attr -n "type" -v "javax.sql.DataSource" \
-i //ResourceTMP -t attr -n "driverClassName" -v "com.mysql.jdbc.Driver" \
-i //ResourceTMP -t attr -n "url" -v "jdbc:mysql://DBHOST:DBPORT/DBNAME?createDatabaseIfNotExist=false&useUnicode=true&characterEncoding=utf-8" \
-i //ResourceTMP -t attr -n "username" -v "DBUSER" \
-i //ResourceTMP -t attr -n "password" -v "DBPASS" \
-i //ResourceTMP -t attr -n "maxActive" -v "150" \
-i //ResourceTMP -t attr -n "maxIdle" -v "10" \
-i //ResourceTMP -t attr -n "initialSize" -v "10" \
-i //ResourceTMP -t attr -n "validationQuery" -v "SELECT 1" \
-i //ResourceTMP -t attr -n "testOnBorrow" -v "true" \
-r //ResourceTMP -v Resource \
server.xml
fi
The trick is to temporarily give a unique name to the new element, so that it can be found later with an XPATH expression. After all attributes have been added, the name is changed back to Resource (with -r).
诀窍是暂时为新元素指定一个唯一名称,以便稍后可以使用 XPATH 表达式找到它。添加所有属性后,名称将更改回 Resource(使用 -r)。
The meaning of the other xmlstarlet options:
其他 xmlstarlet 选项的含义:
-P (or --pf) - preserve original formatting
-S (or --ps) - preserve non-significant spaces
-L (or --inplace) - edit file inplace
回答by Richard Walker
From version 1.4.0 of XMLStarlet (dated 2012-08-26), you can use $prev(or $xstar:prev) as the argument to -i, -a, and -sto refer to the last nodeset inserted. See the examples in the XMLStarlet source code in the files doc/xmlstarlet.txt, examples/ed-backref1, examples/ed-backref2, and examples/ed-backref-delete. You no longer need to use the trick of inserting the element with a temporary element name and then renaming it at the end. The example examples/ed-backref2is particularly helpful in showing how to define a variable to use to refer to a (the) previously-created note so that you don't need to do tricks such as $prev/..to "navigate" out of a node.
从XMLStarlet(日期为2012年8月26日)的版本1.4.0,您可以使用$prev(或$xstar:prev)作为参数-i,-a以及-s指插入的最后节点集。看到XMLStarlet源代码示例中的文件doc/xmlstarlet.txt,examples/ed-backref1,examples/ed-backref2,和examples/ed-backref-delete。您不再需要使用临时元素名称插入元素然后在最后重命名它的技巧。该示例examples/ed-backref2特别有助于展示如何定义一个变量以用于引用(该)先前创建的注释,这样您就无需执行诸如$prev/..“导航”节点之类的技巧。
回答by George Smith
The example did not work until I wrapped <GlobalNamingResources>into a <Server>element.
直到我包装<GlobalNamingResources>到一个<Server>元素中,这个例子才起作用。
回答by dev
I tried the trick from cellux above.,It worked great! Thanks!! But, the formatting was not persisted, just to try, I got rid of options -P and -S, and the formatting issues were gone! I am using CentOS. May be this can help someone.
我尝试了上面 cellux 的技巧。,效果很好!谢谢!!但是,格式没有保留,只是为了尝试,我摆脱了选项 -P 和 -S,格式问题消失了!我正在使用 CentOS。可能这可以帮助某人。

