脚本:在XML文件的标签中提取值最简单的方法是什么?


14

我想读取pom.xml(Maven的“项目对象模型”)并提取版本信息。这是一个例子:

<?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>
    <groupId>com.mycompany</groupId>
    <artifactId>project-parent</artifactId>
    <name>project-parent</name>
    <version>1.0.74-SNAPSHOT</version>
    <dependencies>
        <dependency>
        <groupId>com.sybase.jconnect</groupId>
        <artifactId>jconnect</artifactId>
        <version>6.05-26023</version>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jdmk</groupId>
        <artifactId>jmxtools</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>2.4</version>
    </dependency>       
</dependencies>
</project>

如何从上方提取版本“ 1.0.74-SNAPSHOT”?

希望能够使用简单的bash脚本sed或awk做到这一点。否则,首选简单的python。

编辑

  1. 约束

    linux盒位于公司环境中,因此我只能使用已经安装的工具(不是我不能请求xml2之类的实用程序,但是我必须经过很多繁文ta节)。一些解决方案非常好(已经学习了一些新技巧),但是由于环境受限,它们可能不适用

  2. 更新的xml清单

    我将依赖项标签添加到原始列表中。这将显示某些hacky解决方案在这种情况下可能无法正常工作

  3. 发行版

    我正在使用的发行版是RHEL4



并不是的。xml中有很多版本标签(例如,在依赖标签下)。我只是想“/项目/版本”
安东尼港

哪些与xml相关的工具和库可用?基于jvm的解决方案可以吗?
六。

到目前为止,我可以告诉xml2,xmlgrep和perl XML模块不存在。存在大多数UNIX命令行实用程序。该发行版是红帽EL 4
安东尼香港

(我不能添加评论,所以我有一个答案回答,有点矫枉过正)一些伟大的答案可以在这里找到..... stackoverflow.com/questions/2735548/...
JStrahl

Answers:


17

xml2可以将xml转换为行格式或从行格式转换为xml:

xml2 < pom.xml  | grep /project/version= | sed 's/.*=//'

6

其他方式:xmlgrep和XPath:

xmlgrep --text_only '/project/version' pom.xml

缺点:速度慢


命令更新为xml_grep
GAD3R,

6

使用 python

$ python -c 'from xml.etree.ElementTree import ElementTree; print ElementTree(file="pom.xml").findtext("{http://maven.apache.org/POM/4.0.0}version")'
1.0.74-SNAPSHOT

使用 xmlstarlet

$ xml sel -N x="http://maven.apache.org/POM/4.0.0" -t -m 'x:project/x:version' -v . pom.xml
1.0.74-SNAPSHOT

使用 xmllint

$ echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:version/text()' | xmllint --shell pom.xml | grep -v /
1.0.74-SNAPSHOT

cat (//x:version)[1]/text()使用xmllint时还可以!
kev

5

Clojure的方式。只需要带有特殊jar文件的jvm:

java -cp clojure.jar clojure.main -e "(use 'clojure.xml) (->> (java.io.File. \"pom.xml\") (clojure.xml/parse) (:content) (filter #(= (:tag %) :version)) (first) (:content) (first) (println))"

Scala方式:

java -Xbootclasspath/a:scala-library.jar -cp scala-compiler.jar scala.tools.nsc.MainGenericRunner -e 'import scala.xml._; println((XML.load(new java.io.FileInputStream("pom.xml")) match { case <project>{children @ _*}</project> => for (i <- children if (i  match { case <version>{children @ _*}</version> => true; case _ => false;  }))  yield i })(0) match { case <version>{Text(x)}</version> => x })'

时髦的方式:

java -classpath groovy-all.jar groovy.ui.GroovyMain -e 'println (new XmlParser().parse(new File("pom.xml")).value().findAll({ it.name().getLocalPart()=="version" }).first().value().first())'

这太棒了!好点子!
安东尼·孔

4

这是Perl中的替代方法

$ perl -MXML::Simple -e'print XMLin("pom.xml")->{version}."\n"'
1.0.74-SNAPSHOT

它与问题的修订/扩展示例一起使用,该问题在不同深度具有多个“版本”元素。


速度慢(尽管比xmlgrep快)
Vi。

3

骇客方式:

perl -e '$_ = join "", <>; m!<project[^>]*>.*\n(?:    |\t)<version[^>]*>\s*([^<]+?)\s*</version>.*</project>!s and print "$1\n"' pom.xml

依靠所需的正确缩进 <version>


感谢您的建议,但是很遗憾,它不会返回我想要的内容。请查看更新的pom模型。
安东尼·孔

返回“ 1.0.74-SNAPSHOT”。请注意,在阅读了许多<version>内容之后,我更改了脚本。
六。

注意:此解决方案仅出于娱乐目的而提供,不能在实际产品中使用。最好使用xml2 / xmlgrep / XML :: Simple解决方案。
六。

谢谢!即使它只是“为了好玩”,但到目前为止它可能是“最合适的”解决方案,因为它具有最少的依赖项:它只需要perl ;-)
Anthony Kong

用Java做什么呢?使用pom文件意味着已安装JVM。
六。

3

制定一个非常笨拙的单线解决方案

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [n for n in dom.getElementsByTagName('version') if n.parentNode == dom.childNodes[0]][0].toxml()" | sed -e "s/.*>\(.*\)<.*/\1/g"

sed的结尾非常丑陋,但我无法仅凭心态打印出节点的文本。

从_Vi更新

更少hacky的Python版本:

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [i.childNodes.item(0).nodeValue for i in dom.firstChild.childNodes if i.nodeName == 'version'].pop()"

来自我的更新

另一个版本:

    python -c "from  xml.dom.minidom import parse;dom = parse('pom.xml');print [n.firstChild.data for n in dom.childNodes[0].childNodes if n.firstChild and n.tagName == 'version']"

2

XSLT方式:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>

        <xsl:template match="/">
                <xsl:for-each select="*[local-name()='project']">
                    <xsl:for-each select="*[local-name()='version']">
                        <xsl:value-of select="text()"/>
                    </xsl:for-each>
                </xsl:for-each>
        </xsl:template>
</xsl:stylesheet>
xalan -xsl x.xsl -in pom.xml

如果xsltproc在您的系统上,并且可能与libxslt在RHEL4上一样,则可以使用它和上面的样式表来输出标记,即xsltproc x.xsl prom.xsl。
fpmurphy 2011年

2

如果“ xml中有很多版本标记”,那么您最好忘记使用“简单工具”和正则表达式来做到这一点,而这样做不会。

试试这个python(没有依赖):

from xml.dom.minidom import parse

dom = parse('pom.xml')
project = dom.getElementsByTagName('project')[0]
for node in project.childNodes:
    if node.nodeType == node.ELEMENT_NODE and node.tagName == 'version':
        print node.firstChild.nodeValue

该脚本的作用是什么?
西蒙·希恩

它将使用Python的minidom实现将XML作为DOM结构加载:docs.python.org/library/xml.dom.minidom.html,其想法是获取唯一的<project>标记,然后遍历其子节点(直接(仅适用于childs)找到我们要查找的标签<version>,而不是其他位置具有相同名称的其他标签。
Samus_ 2011年

1

这是使用sed的单线:

sed '/<dependencies>/,/<\/dependencies>/d;/<version>/!d;s/ *<\/\?version> *//g' pom.xml

1
<version>依赖于元素中不存在参数,并且额外的s只能位于依赖项之内。
六。

1

awk可以正常工作,而无需使用任何其他工具。
cat pod.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.networks.app</groupId>
  <artifactId>operation-platform</artifactId>
  <version>1.0.0</version>
  <packaging>tar.xz</packaging>
  <description>POM was created by Sonatype Nexus</description>
</project>

获取<packaging>标签值的简单明了的方法:

cat pod.xml | awk -F'[<>]' '/packaging/{print $3}'

1
这看起来确实可行,但是要注意:将字段分隔符(FS)设置为字符集<和>;然后找到所有包含“包装”一词的行,并给您第三个字段。
SMerrill8

0
Return_text_val=$(xmllint --xpath "//*[local-name()='$TagElmnt']" $FILE )

在这里,尝试一下:

$TagElmnt - TagName
$FILE - xml file to parse

0

我知道您的问题是Linux,但是如果您需要在Windows上执行此操作而无需任何第三方工具(例如可以将其放入批处理文件中),Powershell可以像这样从pom.xml文件中提取任何节点:

powershell -Command "& {select-xml //pom:project/pom:properties/pom:mypluginversion -path pom.xml -Namespace  @{pom='http://maven.apache.org/POM/4.0.0'} | foreach {$_.Node.Innerxml}}" > myPluginVersion.txt

Powershell现在是开源的,并且可以在Linux和其他平台上运行。我们将其用于优先于bash,cygwin和ming64的构建。
Charlweed

0
sed -n "/<name>project-parent/{n;s/.*>\(.*\)<.*/\1/p;q}" pom.xml

-n选项避免打印不匹配的行;第一个匹配项(/.../)在包含所需文本的行之前;该n命令将跳至下一行,在该行中s通过捕获组(\(...\))和向后引用(\1)提取相关信息。p打印出来,q退出。


2
您能否扩大答案以解释这一点?谢谢。
fixer1234
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.