如何使用 xmlstarlet 打印 XPath 匹配的位置?
How to print the location of an XPath match with xmlstarlet?
我想在 pom.xml 文件中找到对 SNAPSHOT 版本的引用。让我们以位于 here 的 POM 文件为例。我想出了以下命令来查找包含字符串 SNAPSHOT:
的元素
$ xmlstarlet sel -t -m "//*[contains(text(), 'SNAPSHOT')]" -v . -n pom.xml
0.2-SNAPSHOT
4.12-SNAPSHOT
1.9.13-SNAPSHOT
20.0-SNAPSHOT
然而,正如上面所见,这只给我匹配本身的文本。我想看到的是关于匹配位置的更多上下文,例如通向匹配元素的路径,如下所示:
$ xmlstarlet magical arguments
/project/version: 0.2-SNAPSHOT
/project/dependencies/dependency: 4.12-SNAPSHOT
/project/properties/jackson.version: 1.9.13-SNAPSHOT
/project/properties/guava.version: 20.0-SNAPSHOT
或者,将 XML 的精简版本作为输出也适用于我,例如:
$ xmlstarlet magical arguments
<project>
<version>0.2-SNAPSHOT</version>
<dependencies>
<dependency>
<version>4.12-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<jackson.version>1.9.13-SNAPSHOT</jackson.version>
<guava.version>20.0-SNAPSHOT</guava.version>
</properties>
</project>
是否可以打印这些或其他类型的匹配发生位置的指示?
我无法使用选择工具生成所需的结果。不过,我确实设法修改了生成的 XSL 以满足您的需要。
我使用 -C
开关生成了 XSL:
xmlstarlet sel -C -t -m "//*[contains(text(), 'SNAPSHOT')]" -m 'ancestor-or-self::*' -v 'name()' -o / -n
输出:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//*[contains(text(), 'SNAPSHOT')]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:text>/</xsl:text>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
然后我应用了以下补丁:
11d10
< <xsl:value-of select="' '"/>
12a12,13
> <xsl:value-of select="text()"/>
> <xsl:value-of select="' '"/>
导致:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//*[contains(text(), 'SNAPSHOT')]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:text>/</xsl:text>
</xsl:for-each>
<xsl:value-of select="text()"/>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
如果将此转换应用到原始 xml 文件,您将获得所需的结果:
xmlstarlet tr modified.xsl input.xml
输出:
project/version/0.2-SNAPSHOT
project/dependencies/dependency/version/4.12-SNAPSHOT
project/properties/jackson.version/1.9.13-SNAPSHOT
project/properties/guava.version/20.0-SNAPSHOT
我想出了以下方法来制作 XML 的精简版:
xmlstarlet ed -d "//*[count((.|.//*)[contains(text(), 'SNAPSHOT')]) = 0]" pom.xml
输出:
<?xml version="1.0"?>
<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">
<version>0.2-SNAPSHOT</version>
<dependencies>
<dependency>
<version>4.12-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<jackson.version>1.9.13-SNAPSHOT</jackson.version>
<guava.version>20.0-SNAPSHOT</guava.version>
</properties>
</project>
我们的想法是删除不包含文本 SNAPSHOT 的每个节点,也没有包含它的任何后代。我真的不喜欢我必须使用 (.|.//*)
来匹配当前节点或其后代,一定有更好的方法,但我发现普通的 .//*
与当前节点不匹配, 只有它的后代。
xmlstarlet 可以使用打破嵌套的 -b
选项生成请求的输出:
xmlstarlet sel -t \
-m "//*[contains(text(),'SNAPSHOT')]" \
-m 'ancestor::*' -v 'name()' -o '/' \
-b -v "concat(name(),': ',.)" -n pom.xml
输出:
project/version: 0.2-SNAPSHOT
project/dependencies/dependency/version: 4.12-SNAPSHOT
project/properties/jackson.version: 1.9.13-SNAPSHOT
project/properties/guava.version: 20.0-SNAPSHOT
我想在 pom.xml 文件中找到对 SNAPSHOT 版本的引用。让我们以位于 here 的 POM 文件为例。我想出了以下命令来查找包含字符串 SNAPSHOT:
的元素$ xmlstarlet sel -t -m "//*[contains(text(), 'SNAPSHOT')]" -v . -n pom.xml
0.2-SNAPSHOT
4.12-SNAPSHOT
1.9.13-SNAPSHOT
20.0-SNAPSHOT
然而,正如上面所见,这只给我匹配本身的文本。我想看到的是关于匹配位置的更多上下文,例如通向匹配元素的路径,如下所示:
$ xmlstarlet magical arguments
/project/version: 0.2-SNAPSHOT
/project/dependencies/dependency: 4.12-SNAPSHOT
/project/properties/jackson.version: 1.9.13-SNAPSHOT
/project/properties/guava.version: 20.0-SNAPSHOT
或者,将 XML 的精简版本作为输出也适用于我,例如:
$ xmlstarlet magical arguments
<project>
<version>0.2-SNAPSHOT</version>
<dependencies>
<dependency>
<version>4.12-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<jackson.version>1.9.13-SNAPSHOT</jackson.version>
<guava.version>20.0-SNAPSHOT</guava.version>
</properties>
</project>
是否可以打印这些或其他类型的匹配发生位置的指示?
我无法使用选择工具生成所需的结果。不过,我确实设法修改了生成的 XSL 以满足您的需要。
我使用 -C
开关生成了 XSL:
xmlstarlet sel -C -t -m "//*[contains(text(), 'SNAPSHOT')]" -m 'ancestor-or-self::*' -v 'name()' -o / -n
输出:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//*[contains(text(), 'SNAPSHOT')]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:text>/</xsl:text>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
然后我应用了以下补丁:
11d10
< <xsl:value-of select="' '"/>
12a12,13
> <xsl:value-of select="text()"/>
> <xsl:value-of select="' '"/>
导致:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//*[contains(text(), 'SNAPSHOT')]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:text>/</xsl:text>
</xsl:for-each>
<xsl:value-of select="text()"/>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
如果将此转换应用到原始 xml 文件,您将获得所需的结果:
xmlstarlet tr modified.xsl input.xml
输出:
project/version/0.2-SNAPSHOT
project/dependencies/dependency/version/4.12-SNAPSHOT
project/properties/jackson.version/1.9.13-SNAPSHOT
project/properties/guava.version/20.0-SNAPSHOT
我想出了以下方法来制作 XML 的精简版:
xmlstarlet ed -d "//*[count((.|.//*)[contains(text(), 'SNAPSHOT')]) = 0]" pom.xml
输出:
<?xml version="1.0"?>
<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">
<version>0.2-SNAPSHOT</version>
<dependencies>
<dependency>
<version>4.12-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<jackson.version>1.9.13-SNAPSHOT</jackson.version>
<guava.version>20.0-SNAPSHOT</guava.version>
</properties>
</project>
我们的想法是删除不包含文本 SNAPSHOT 的每个节点,也没有包含它的任何后代。我真的不喜欢我必须使用 (.|.//*)
来匹配当前节点或其后代,一定有更好的方法,但我发现普通的 .//*
与当前节点不匹配, 只有它的后代。
xmlstarlet 可以使用打破嵌套的 -b
选项生成请求的输出:
xmlstarlet sel -t \
-m "//*[contains(text(),'SNAPSHOT')]" \
-m 'ancestor::*' -v 'name()' -o '/' \
-b -v "concat(name(),': ',.)" -n pom.xml
输出:
project/version: 0.2-SNAPSHOT
project/dependencies/dependency/version: 4.12-SNAPSHOT
project/properties/jackson.version: 1.9.13-SNAPSHOT
project/properties/guava.version: 20.0-SNAPSHOT