xmlstarlet 添加具有命名空间和属性的元素

xmlstarlet add element with namespace and attributes

我正在尝试将具有名称空间和属性的节点添加到 xml,但如果我尝试在 xmlstarlet 的一次执行中将其作为多个命令来执行,则会失败:

<?xml version="1.0"?>
<levela xmlns:xi="http://www.w3.org/2001/XInclude">
  <levelb>
  </levelb>
</levela>

xmlstarlet ed -L -s /levela/levelb -t elem -n xi:input -i //xi:input -t attr -n "href" -v "aHref" file.xml

我正在尝试获取:

<?xml version="1.0"?>
<levela xmlns:xi="http://www.w3.org/2001/XInclude">
  <levelb>
     <xi:input href="aHref"/>
  </levelb>
</levela>

但是没有添加属性。所以我得到:

<?xml version="1.0"?>
<levela xmlns:xi="http://www.w3.org/2001/XInclude">
  <levelb>
     <xi:input/>
  </levelb>
</levela>

如果我 运行 它像这样执行两次,它就会工作:

xmlstarlet ed -L -s /levela/levelb -t elem -n xi:input file.xml

xmlstarlet ed -L -i //xi:input -t attr -n "href" -v "aHref" file.xml

如果我添加一个没有命名空间的标签,它也有效,例如:

xmlstarlet ed -L -s /levela/levelb -t elem -n levelc -i //levelc -t attr -n "href" -v "aHref" file.xml

<?xml version="1.0"?>
<levela xmlns:xi="http://www.w3.org/2001/XInclude">
  <levelb>
     <levelc href="aHref"/>
  </levelb>
</levela>

我做错了什么?为什么它不适用于命名空间?

您似乎无法将属性和属性值插入命名空间节点...也许更聪明的人可以想出别的办法,但至少在这种情况下,我能解决这个问题的唯一方法是这个:

 xmlstarlet ed -N xi="http://www.w3.org/2001/XInclude" --subnode "//levela/levelb" \
 --type elem -n "xi:input" --insert  "//levela/levelb/*"  --type attr --name "href"\
 --value "aHref" file.xml

这样做就可以了:

xmlstarlet edit \
  -s '/levela/levelb' -t elem -n 'xi:input' \
  -s '$prev' -t attr -n 'href' -v 'aHref' \
file.xml

xmlstarlet edit 代码可以使用方便的 $prev (又名 $xstar:prev) 变量引用最多创建的节点 最近的 -i (--insert)-a (--append)-s (--subnode) 选项。 $prev 的例子在 doc/xmlstarlet.txt 和 源代码的 examples/ed-backref*.

可以使用 -i-a-s 添加属性。

What am I doing wrong? Why doesn't it work with the namespace?

更新 2022-04-15
您使用的 -i '//xi:input' … 语法是完全合乎逻辑的。身为你的 拥有 2 个替代命令表明它是命名空间 xi 触发遗漏并且在 edInsert 函数中有一个提示 源代码的 src/xml_edit.c 它说 NULL /* TODO: NS */。 当你与 xmlstarlet 合作过一些 是时候接受(或不接受)它的限制了;在这种情况下 $prev 反向引用很有用。我不希望 TODO 尽快离开。
(结束更新)

嗯,我认为 xmlstarlet edit 将节点命名视为用户 责任,如下例所示,

printf '<v/>' |
xmlstarlet edit --omit-decl \
  -s '*' -t elem -n 'undeclared:qname' -v 'x' \
  -s '*' -t elem -n '!--' -v ' wotsinaname ' \
  -s '$prev' -t attr -n ' "" ' -v '' \
  -s '*' -t elem -n ' <&> ' -v 'harrumph!' 

输出显然不是XML:

<v>
  <undeclared:qname>x</undeclared:qname>
  <!--  "" =""> wotsinaname </!-->
  < <&> >harrumph!</ <&> >
</v>

如果要缩进新元素,例如:

xmlstarlet edit \
  -s '/levela/levelb' -t elem -n 'xi:input' \
  --var newnd '$prev' \
  -s '$prev' -t attr -n 'href' -v 'aHref' \
  -a '$newnd' -t text -n ignored -v '' \
  -u '$prev' -x '(//text())[1][normalize-space()=""]' \
file.xml

-x XPath 表达式获取提供的第一个文本节点 只包含空格,即 levela 的第一个子节点。 --var name xpath 选项定义 xmlstarlet edit 中提到了变量 doc/xmlstarlet.txt 但不在用户指南中。

我用的是xmlstarlet版本1.6.1.