如何使用Xmlstarlet在XML文件中添加新元素



我想编辑一个XML文件并向其添加2个新元素。我可以添加一个新元素,但第二个元素不能正确添加。

context.xml文件-

<?xml version="1.0" encoding="UTF-8"?>
<Context>
</Context>

期望输出-

<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/DBRead" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/DBRead"
username="abc" password="xyz" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
<Resource name="jdbc/DBWrite" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/DBWrite"
username="abc" password="xyz" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
</Context>

我已经编写了以下脚本来添加两个新的Resource标签,但只有一个资源标签被正确添加-

changeXml.sh -

#!/bin/sh
xmlstarlet ed -L -s '//Context' -t elem -n 'Resource' -s '//Context/Resource' -t attr -n 'name' -v 'jdbc/DBRead' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'auth' -v 'Container' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'type' -v 'javax.sql.DataSource' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'driverClassName' -v 'org.postgresql.Driver' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'url' -v 'jdbc:postgresql://127.0.0.1:5432/DBRead' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'username' -v 'abc' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'password' -v 'xyz' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxTotal' -v '20' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxIdle' -v '10' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxWaitMillis' -v '-1' /home/context.xml;
xmlstarlet ed -L -s '//Context' -t elem -n 'Resource' -s '//Context/Resource' -t attr -n 'name' -v 'jdbc/DBWrite' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'auth' -v 'Container' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'type' -v 'javax.sql.DataSource' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'driverClassName' -v 'org.postgresql.Driver' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'url' -v 'jdbc:postgresql://127.0.0.1:5432/DBWrite' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'username' -v 'abc' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'password' -v 'xyz' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxTotal' -v '20' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxIdle' -v '10' /home/context.xml;
xmlstarlet ed -L -s '//Context/Resource' -t attr -n 'maxWaitMillis' -v '-1' /home/context.xml;

这个脚本的输出是-

<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/DBRead" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/DBRead"
username="abc" password="xyz" maxTotal="20" maxIdle="10"
maxWaitMillis="-1" name="jdbc/DBRead"/>
<Resource name="jdbc/DBRead"/>
</Context>

给出错误-Attribute name redefined并产生上述输出。请建议如何得到预期的输出。我还尝试将第二个Resource元素重命名为ResourceTMP,但这也给了我相同的输出。提前谢谢。

您可以将set -x添加为脚本的第二行,这将使每一行在执行之前都返回,更容易找到错误的原因:

输出如下所示:

$ ./changeXml.sh
+ xmlstarlet ed -L -s //Context -t elem -n Resource -s //Context/Resource -t attr -n name -v jdbc/DBRead context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n auth -v Container context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n type -v javax.sql.DataSource context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n driverClassName -v org.postgresql.Driver context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n url -v jdbc:postgresql://127.0.0.1:5432/DBRead context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n username -v abc context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n password -v xyz context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n maxTotal -v 20 context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n maxIdle -v 10 context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n maxWaitMillis -v -1 context.xml -b
failed to load external entity "-b"
+ xmlstarlet ed -L -s //Context -t elem -n Resource -s //Context/Resource -t attr -n name -v jdbc/DBWrite context.xml
+ xmlstarlet ed -L -s //Context/Resource -t attr -n auth -v Container context.xml
context.xml:3.101: Attribute name redefined
password="xyz" maxTotal="20" maxIdle="10" maxWaitMillis="-1" name="jdbc/DBWrite"
         ^
+ xmlstarlet ed -L -s //Context/Resource -t attr -n type -v javax.sql.DataSource context.xml
context.xml:3.101: Attribute name redefined
password="xyz" maxTotal="20" maxIdle="10" maxWaitMillis="-1" name="jdbc/DBWrite"
...

错误出现在包含:

的行
xmlstarlet ed -L -s //Context/Resource -t attr -n maxWaitMillis -v -1 context.xml -b

xmlstarlet ed --help

没有显示-b选项

我认为你应该先修复这个错误,然后再修复下面的错误:

xmlstarlet ed -L -s //Context/Resource -t attr -n auth -v Container context.xml

这可能是由于脚本中的前一行似乎也添加了一个名为auth的属性。

编辑:

  1. 我删除了每行末尾的;
  2. 当添加1个元素或1个属性时,我删除了if '//'的使用。您可以使用index(如[1])来访问正确的节点。

修改后的脚本如下:

#!/bin/sh
#set -x
xmlstarlet ed -L -s '/Context' -t elem -n 'Resource' -s '/Context/Resource[1]' -t attr -n 'name' -v 'jdbc/DBRead' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'auth' -v 'Container' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'type' -v 'javax.sql.DataSource' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'driverClassName' -v 'org.postgresql.Driver' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'url' -v 'jdbc:postgresql://127.0.0.1:5432/DBRead' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'username' -v 'abc' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'password' -v 'xyz' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'maxTotal' -v '20' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'maxIdle' -v '10' context.xml
xmlstarlet ed -L -s '/Context/Resource[1]' -t attr -n 'maxWaitMillis' -v '-1' context.xml
xmlstarlet ed -L -s '/Context' -t elem -n 'Resource' -s '/Context/Resource[2]' -t attr -n 'name' -v 'jdbc/DBWrite' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'auth' -v 'Container' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'type' -v 'javax.sql.DataSource' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'driverClassName' -v 'org.postgresql.Driver' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'url' -v 'jdbc:postgresql://127.0.0.1:5432/DBWrite' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'username' -v 'abc' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'password' -v 'xyz' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'maxTotal' -v '20' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'maxIdle' -v '10' context.xml
xmlstarlet ed -L -s '/Context/Resource[2]' -t attr -n 'maxWaitMillis' -v '-1' context.xml
xmlstarlet fo context.xml
  • 我注释了第二行(所以我不再看到每一行执行
  • 我添加了xmlstarlet fo context.xml来在所有执行后立即检查内容。

最后XML看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/DBRead" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432/DBRead" username="abc" password="xyz" maxTotal="20" maxIdle="10" maxWaitMillis="-1"/>
<Resource name="jdbc/DBWrite" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432/DBWrite" username="abc" password="xyz" maxTotal="20" maxIdle="10" maxWaitMillis="-1"/>
</Context>

xmlstarlet edit支持多种编辑操作。后应该在单个调用中生成所需的输出:

xmlstarlet edit -L 
-s '*' -t 'elem' -n 'Resource' 
--var r1 '$prev' 
-s '*' -t 'elem' -n 'Resource' 
--var r2 '$prev' 
-s '$r1' -t 'attr' -n 'name' -v 'jdbc/DBRead' 
-s '$r1' -t 'attr' -n 'auth' -v 'Container' 
-s '$r1' -t 'attr' -n 'type' -v 'javax.sql.DataSource' 
…
-s '$r1' -t 'attr' -n 'maxWaitMillis' -v '-1' 
-u '$r2' -x '$r1/@*' 
-u '$r2/@name' -v 'jdbc/DBWrite' 
-u '$r2/@url' -x 'concat(substring-before(.,"/DBRead"),"/DBWrite")' 
-i '*/*' -t 'text' -n 'ignored' -v '  ' 
-a '*/*' -t 'text' -n 'ignored' -v '' 
-u '$prev' -x 'substring('"$(printf '"nA"')"',1,1)' 
file.xml

地点:

  • --var定义了一个命名变量,$prev变量引用到由最近的-s-i-a选项创建的节点它们都定义或重新定义了它(看到了吗xmlstarlet.txt--var$prev为例)
  • 是省略的-s选项所属的地方
  • 然后,创建第二个Resource元素作为第一个元素的副本编辑使两个DBWrite节点右
  • 最后3个动作处理缩进

相关内容

  • 没有找到相关文章

最新更新