代码之家  ›  专栏  ›  技术社区  ›  Zoltan

如何打印与xmlstarlet匹配的xpath的位置?

  •  0
  • Zoltan  · 技术社区  · 7 年前

    我想在pom.xml文件中找到对快照版本的引用。让我们使用位于 here 例如。我使用以下命令查找包含字符串快照的元素:

    $ 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>
    

    是否可以打印这些或其他类型的匹配发生位置指示?

    2 回复  |  直到 7 年前
        1
  •  1
  •   Thor    7 年前

    我无法用选择工具生成所需的结果。但是,我确实设法修改了生成的XSL以满足您的需要。

    我用 -C 开关:

    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="'&#10;'"/>
          </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()&gt;1]">
          <xsl:value-of select="'&#10;'"/>
          <xsl:value-of select="."/>
        </xsl:for-each>
      </xsl:template>
    </xsl:stylesheet>
    

    然后我应用了以下补丁:

    11d10
    <         <xsl:value-of select="'&#10;'"/>
    12a12,13
    >       <xsl:value-of select="text()"/>
    >       <xsl:value-of select="'&#10;'"/>
    

    导致:

    <?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="'&#10;'"/>
        </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()&gt;1]">
          <xsl:value-of select="'&#10;'"/>
          <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
    
        2
  •  0
  •   Zoltan    7 年前

    我想出了以下方法来生成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>
    

    其思想是删除不包含文本快照也没有包含文本快照的任何子代的每个节点。我真的不喜欢我不得不用 (.|.//*) 要匹配当前节点或其后代,必须有更好的方法,但我发现 .//* 不匹配当前节点,只匹配其后代。

    推荐文章