我有一个XML文件,如:
<?xml version="1.0" encoding="utf-8"?>
<project>
<data>
<modelType type="InstantMessage">
<model type="InstantMessage" id="1" >
<modelField name="From" type="Party">
<model type="Party" id="123456">
<field name="Identifier" type="String">
<value type="String">foo</value>
</field>
</model>
</modelField>
<multiModelField name="To" type="Party" />
<field name="Body" type="String">
<value type="String">bar</value>
</field>
<field name="TimeStamp" type="TimeStamp">
<value type="TimeStamp">2016-07-11 13:26:38+02:00</value>
</field>
</model>
</modelType>
</data>
我确实希望通过一个查询生成以下结果:
foo|bar
嵌套在不同级别时,我不知道如何访问这些字段。我试过像:
root@machine:/.../# xmlstarlet sel -T -t -m /project/data/modelType/model -v "concat(/modelField/model/field/value'|'/field[@Body]/value)" file.xml
但是我通过xmlstarlet永久地获得了语法错误。我不明白如何在manual中使用它。在这种情况下有谁知道如何使用xmlstarlet?
谢谢,彼得
答案 0 :(得分:4)
您的XML文件(如所示)缺少<project>
的关闭标记;这将导致解析错误,这将阻止xmlstarlet
能够执行查询。
查询本身有一些问题:在
中 concat函数的语法是concat(a,b,c)
;你的调用不包括逗号。
在匹配中,xpaths是相对于匹配的节点。但是concat中的第一个元素是:
/modelField/model/field/value
是绝对的,所以它只能匹配根,而它不匹配。你需要一个相对表达式:
modelField/model/field/value
或
./modelField/model/field/value
最后一个xpath:
/field[@Body]/value
找不到,因为field
不是根元素,没有/
它也不匹配,因为field
不是匹配节点的直接子节点。在这里,你可以拼写出匹配节点的路径,如上所述,或使用//
选择任何子节点:
.//field[@Body]/value
但是,说明符[@Body]
不正确。如上所述,如果元素具有名为Body
的属性,则选择器成功。您正在尝试将元素与名为name
的属性匹配,该属性的值为Body
,您将其写为[@name="Body"]
。引号是必需的,这意味着您需要在表达式周围使用单引号或反斜杠 - 转义引号。
将所有内容放在一起,一旦修复了XML文件,就可以使用:
xmlstarlet sel -T \
-t -m /project/data/modelType/model \
-v 'concat(modelField/model/field/value,"|",.//field[@name="Body"]/value)' \
file.xml
concat
调用不是必需的,因为您可以使用多个-v
选项,-o
输出固定字符串。您可能会发现以下内容更具可读性:
xmlstarlet sel -T \
-t -m '/project/data/modelType/model' \
-v './/field[@name="Identifier"]/value' \
-o '|' \
-v './/field[@name="Body"]/value' \
file.xml