xmlstarlet:使用单个查询查询和连接嵌套的子元素

时间:2016-07-19 15:26:31

标签: xml parsing xmlstarlet

我有一个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?

谢谢,彼得

1 个答案:

答案 0 :(得分:4)

您的XML文件(如所示)缺少<project>的关闭标记;这将导致解析错误,这将阻止xmlstarlet能够执行查询。

查询本身有一些问题:在

  1. concat函数的语法是concat(a,b,c);你的调用不包括逗号。

  2. 在匹配中,xpaths是相对于匹配的节点。但是concat中的第一个元素是:

    /modelField/model/field/value
    

    是绝对的,所以它只能匹配根,而它不匹配。你需要一个相对表达式:

    modelField/model/field/value
    

    ./modelField/model/field/value
    

    最后一个xpath:

    /field[@Body]/value
    
    找不到

    ,因为field不是根元素,没有/它也不匹配,因为field不是匹配节点的直接子节点。在这里,你可以拼写出匹配节点的路径,如上所述,或使用//选择任何子节点:

    .//field[@Body]/value
    
  3. 但是,说明符[@Body]不正确。如上所述,如果元素具有名为Body的属性,则选择器成功。您正在尝试将元素与名为name的属性匹配,该属性的值为Body,您将其写为[@name="Body"]。引号是必需的,这意味着您需要在表达式周围使用单引号或反斜杠 - 转义引号。

  4. 将所有内容放在一起,一旦修复了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