【问题标题】:XMLStarlet does not select anythingXMLStarlet 不选择任何内容
【发布时间】:2012-02-19 23:33:37
【问题描述】:

我有一个典型的 pom.xml,想打印 groupId、artifactId 和 version,用冒号分隔。我认为XMLStarlet 是正确的工具。我尝试了几种方法,但总是得到一个空行。

xml sel -t -m project -v groupId -o : -v artifactId -o : -v version pom.xml

预期输出:

org.something.apps:app-acct:5.4

实际输出:空行

即使我尝试只打印 groupId 我什么也得不到:

xml sel -t -v project/groupId pom.xml

我确信该工具可以看到元素,因为我可以毫无问题地列出它们:

xml el pom.xml

打印以下内容(正确):

project
project/modelVersion
project/parent
project/parent/groupId
project/parent/artifactId
project/parent/version
project/groupId
project/artifactId
project/version
project/packaging

怎么了?

这里是 pom.xml 的精简版:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                        http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.something</groupId>
        <artifactId>base</artifactId>
        <version>1.16</version>
    </parent>

    <groupId>org.something.apps</groupId>
    <artifactId>app-acct</artifactId>
    <version>5.4</version>
    <packaging>war</packaging>

</project>

【问题讨论】:

    标签: command-line-interface pom.xml xmlstarlet


    【解决方案1】:

    更新:从 1.5 版开始,默认命名空间前缀“_”可用,因此解决方案简化为:

    xml sel -t -m _:project -v _:groupId -o : -v _:artifactId -o : -v _:version pom.xml

    感谢@JamieNelson 的提醒。


    不幸的是,XMLStarlet 对默认命名空间非常挑剔。如果文档声明了它(xmlns=),您也必须为 XMLStarlet 声明它,并在元素前面加上您选择的名称(参见 here):

    xml sel -N my=http://maven.apache.org/POM/4.0.0 -t -m my:project -v my:groupId -o : -v my:artifactId -o : -v my :版本 pom.xml

    运行上述命令会得到预期的输出:

    org.something.apps:app-acct:5.4
    

    但是,如果文档没有声明默认命名空间(或者命名空间的 URL 略有不同),上述命令将不起作用,这是一个真正的 PITA。更通用的解决方案是在选择元素之前删除默认命名空间声明。从 XMLStarlet 1.3.1 开始,将 XML 转换为 PYX 格式并返回会删除命名空间声明:

    xml pyx pom.xml | xml p2x | xml sel -t -m project -v groupId -o : -v artifactId -o : -v version 2>nul

    更新 (2014-02-12): 从 XMLStarlet 1.4.2 开始,PYX XML 转换已修复(不删除命名空间声明),因此上述命令将不起作用(感谢彼得格鲁克的提示)。请改用以下命令:

    xml pyx pom.xml | grep -v ^A | xml p2x | xml sel -t -m 项目 -v groupId -o : -v artifactId -o : -v 版本

    注意:上面的 grep 会从文档中删除所有属性,而不仅仅是命名空间声明。对于这种特定情况(从 pom.xml 中选择元素值,其中不期望具有非默认命名空间的元素),这是可以的,但对于一般 XML,您将只删除默认命名空间声明,而不是其他任何内容:

    xml pyx pom.xml | grep -v "^Axmlns" | xml p2x | xml sel -t -m 项目 -v groupId -o : -v artifactId -o : -v 版本


    注意(已过时):错误重定向 (2&gt;nul) 是隐藏对(现在)未知命名空间 xsi 的投诉所必需的:

    -:1.28: 项目中 schemaLocation 的命名空间前缀 xsi 未定义

    另一种摆脱抱怨的方法是删除 schemaLocation 属性(实际上,此命令会从 PYX 文档中删除所有属性,而不仅仅是 xsi:schemaLocation):

    xml pyx pom.xml | grep -v ^A | xml p2x | xml sel -t -m 项目 -v groupId -o : -v artifactId -o : -v 版本

    【讨论】:

    • 您对使用声明的命名空间(别名?)为元素添加前缀的评论是与链接文档的关键区别。
    • 你帮了我很多!谢了!
    【解决方案2】:

    XML-> PYX -> XML 技巧对我不起作用(使用 XMLStarlet 版本 1.4.2)。但是,XMLStarlet documentation 包含这个方便的 sed 命令,它可以从 XML 文档中删除命名空间声明:

    sed -e 's/ xmlns.*=".*"//g'
    

    那行得通。对于原始问题,语法为:

    cat pom.xml | sed -e 's/ xmlns.*=".*"//g' | xml sel -t -m project -v groupId -o : -v artifactId -o : -v version
    

    【讨论】:

    • 感谢有关 PYX -> XML 转换更改的更新。这意味着最后一个命令行(使用 grep -v ^A)现在是首选命令行。但是,sed/grep/awk 等不应用于一般 XML:它适用于文档中的特定简单示例(也适用于我的简化示例),但它很容易创建无效的 XML 文档。示例:在此运行“方便” sed:a="X"; return a; 将导致:
    【解决方案3】:

    从 xmlstarlet 1.2 版开始,您可以这样做:

    xml sel -t -m "//_:project" -v _:groupId -o : -v _:artifactId -o : -v _:version pom.xml
    

    这里还有一些其他选项: http://xmlstar.sourceforge.net/doc/UG/ch05.html

    【讨论】:

    • 在 1.3.1 中:不工作 / 在 1.4.0 中:不工作 / 在 1.6.1 中:工作
    猜你喜欢
    • 1970-01-01
    • 2012-09-20
    • 2017-01-16
    • 2013-08-27
    • 1970-01-01
    • 2017-01-30
    • 2016-12-10
    • 2011-08-16
    • 2018-10-23
    相关资源
    最近更新 更多