使用块中的xmlstarlet从同一节点获取多个子注释

使用块中的xmlstarlet从同一节点获取多个子注释,xml,linux,xpath,xmlstarlet,Xml,Linux,Xpath,Xmlstarlet,我有一个XML文件,其中包含多个用户条目和一些用户数据,如姓名、电子邮件和其他数据。这似乎可以使用多个--value of(-v)参数来完成,如下所示: $ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t --nl -v "//n:title" -v "//n:email" ~/tests/test-xml.xml Some user Some user #2 Some use

我有一个XML文件,其中包含多个用户条目和一些用户数据,如姓名、电子邮件和其他数据。这似乎可以使用多个
--value of
-v
)参数来完成,如下所示:

$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t --nl -v "//n:title" -v "//n:email" ~/tests/test-xml.xml

Some user
Some user #2
Some user #3some.user@example.com
some.user2@example.com
some.user3@example.com
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(concat(current()//n:title, ',', current()//n:email), '|', '')" ~/tests/test-xml.xml | sed -E 's/[,|]+/\n/g'
Some user
some.user@example.com
Some user #2
some.user2@example.com
Some user #3
some.user3@example.com
但是它们不在一起,看起来工具首先处理所有
元素,然后处理所有
元素。我希望采用以下格式:

Some user
some.user@example.com
Some user #2
some.user2@example.com
...
发现我需要xpath函数
concat
。现在我至少用逗号分隔它们:

$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(current()//n:title, ',', current()//n:email)" ~/tests/test-xml.xml
Some user,some.user@example.comSome user #2,some.user2@example.comSome user #3,some.user3@example.com
这正是我需要的,但是当我将
\n
设置为分隔符而不是
时,它将只打印
\n
而不是换行。同样的情况也发生在
\\n
\r\n
上。作为一种解决方法,可以使用sed这样替换它:
sed's/,/\n/g'

然而,这并不能解决
之间没有新行的问题。user@example.comSome用户#2

$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(current()//n:title, ',', current()//n:email)" ~/tests/test-xml.xml | sed 's/,/\n/g'
Some user
some.user@example.comSome user #2
some.user2@example.comSome user #3
some.user3@example.com
我怎样才能意识到这一点?如果有意义且可能的话,您更喜欢不使用额外的
sed
命令的解决方案

变通办法 我找到的唯一解决方法是将其嵌套在另一个
concat
调用中,以添加另一个字符,该字符标识需要另一行的位置,也可以替换为
\n
,如下所示:

$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t --nl -v "//n:title" -v "//n:email" ~/tests/test-xml.xml

Some user
Some user #2
Some user #3some.user@example.com
some.user2@example.com
some.user3@example.com
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(concat(current()//n:title, ',', current()//n:email), '|', '')" ~/tests/test-xml.xml | sed -E 's/[,|]+/\n/g'
Some user
some.user@example.com
Some user #2
some.user2@example.com
Some user #3
some.user3@example.com
尽管这样做有效,但对我来说,这似乎是一个令人讨厌的解决办法。我想知道是否有一个更干净的方法来做到这一点。我想这可能是因为对
xmlstarlet
以及
xpath
有了更深入的体验

测试XML文档

67
1.
100
某用户
一些user@example.com
一些用户#2
一些user2@example.com
一些用户#3
一些user3@example.com

我在这里使用xmllint,但xpath和xargs/printf的使用应该仍然相同:

xmllint --format --xpath "concat('\"',/feed/entry/title,'\" \"',/feed/entry/contributor/email,'\"')" ~/tests/test-xml.xml | xargs printf "%s\n"

使用xpath,我们通过在标题和电子邮件之间添加引号和空格来格式化数据。然后我们通过管道连接到xargs和printf,将每个条目打印在单独的行上。

最简单的方法是在每个
条目之后输出一个换行符(
--nl
):

xmlstarlet sel-N=”http://www.w3.org/2005/Atom“-t-m”//n:entry“-v“n:title”--nl-v“n:contributor/n:email”--nl-input.xml
但这将在输出的末尾输出一个额外的换行符:

某个用户
一些user@example.com
一些用户#2
一些user2@example.com
一些用户#3
一些user3@example.com
另一种方法是在
条目
之前输出一个换行符(如果它不是第一个)。(使用-i(xsl:if)和-b(中断嵌套))

xmlstarlet sel-N=”http://www.w3.org/2005/Atom“-t-m”//n:entry“-i”position()>1”--nl-b-v“n:title”--nl-v“n:contributor/n:email”input.xml
输出:

某个用户
一些user@example.com
一些用户#2
一些user2@example.com
一些用户#3
一些user3@example.com

你就不能只做
-m”//n:entry“-v“n:title”--nl-v“n:contributor/n:email”--nl
?最后会有一个额外的换行符,但希望这不是问题。可以使用xpath 2.0来完成,但为此您需要类似xidel的东西。我的回答有帮助吗,或者您仍然有问题吗?