XmlStarlet是一个xml处理工具。它可按xpath对xml获取元素或者修改元素。
不带参数运行xmlstarlet,就会输出xmlstarlet的功能列表。下面是截取的一部份。
XMLStarlet Toolkit: Command line utilities for XML
Usage: xmlstarlet [] []
where is one of:
ed (or edit) - Edit/Update XML document(s)
sel (or select) - Select data or query XML document(s) (XPATH, etc)
el (or elements) - Display element structure of XML document
其中sel和ed分别是选择和编辑命令,el用于大概浏览xml文档的结构。
浏览xml的结构
以这个pom.xml为例。xmlstarlet el pom.xml
会显示pom.xml的所有节点,结果里的每一行都对应着一条xpath。相同xpath的所有节点都会输出一遍,要想去重,可以使用xmlstarlet el -u pom.xml
。
如果还要显示属性的话,使用-a
,比如xmlstarlet el -a pom.xml
,输出结果中包含下面几行:
project
project/@xmlns
project/@xmlns:xsi
project/@xsi:schemaLocation
project/modelVersion
project/groupId
project/artifactId
其中@开头的xmlns、xmlns:xsi、xsi:schemaLocation是project节点的三个属性,分成了三行显示。
如果要显示属性的值,使用-v
,比如xmlstarlet el -v pom.xml
,输出结果中包含下面几行:
project[@xmlns=’http://maven.apache.org/POM/4.0.0‘ and @xmlns:xsi=’http://www.w3.org/2001/XMLSchema-instance‘ and @xsi:schemaLocation=’http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd‘]
project/modelVersion
project/groupId
其中project的三个属性xmlns、xmlns:xsi、xsi:schemaLocation显示在了一行。
使用xpath选择节点
先介绍简单的没有命名空间的情况,将pom.xml里的xmlns和xsi:schemaLocation属性都删掉,保存成pom2.xml(linux中可使用sed -e 's/ xmlns.*=".*"//g' pom.xml | sed 's/xsi:schemaLocation=".*"//g' > pom2.xml
)。
xmlstarlet sel命令是对xml进行输出的命令。
- 查询pom2.xml里子节点artifactId为leveldb的dependency节点的version节点的文本:
xmlstarlet sel -t -v "//dependency[artifactId='leveldb']/version" -n pom2.xml
这会输出0.7
-t 一般sel命令必须至少有一个-t选项,它指定新的template,代表一项操作。template是xslt中的内容。
-v 是指把xpath取出值打印出来
-n 是指打印一个换行符,可以试试不加-n的效果。 - 打印pom2.xml里所有dependency节点的artifact节点和version节点的文本:
打印artifact节点可以用-v '//dependency/artifactId'
,打印version节点可以用-v '//dependency/version'
,但是输出是先输出所有的artifactId,再输出所有的version。想要每行输出一组的artifactId和version,可以借助-m
选项。xmlstarlet sel -t -m "//dependency" -v "artifactId" -o " " -v "version" -n pom2.xml
-m 按xpath对xml进行匹配,对每个匹配到的节点,用-v输出值。这里是输出一个artifactId,接着输出一个version
-o 是输出一个指定字符串,这里指定的是一个空格,用来隔开artifactId和version
xpath还可以根据属性选择,或者选择属性,或者函数。关于xpath的内容可以去w3cschool看。
xslt
xmlstarlet使用了xslt来选择和输出xml。-t
对应xsl:template
,-v
对应xsl:value-of
xmlstarlet可以打印每个操作的相应的xslt,比如:xmlstarlet sel -C -t -m "//dependency" -v "artifactId" -o " " -v "version" -n pom2.xml
这会输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?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="//dependency"> <xsl:call-template name="value-of-template"> <xsl:with-param name="select" select="artifactId"/> </xsl:call-template> <xsl:text> </xsl:text> <xsl:call-template name="value-of-template"> <xsl:with-param name="select" select="version"/> </xsl:call-template> <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> |
可以看到,-t
对应xsl:template
。 -m "//dependency"
对应<xsl:for-each select="//dependency"
,它的下面包含了两个<xsl:call-template name="value-of-template">
,各对应一个-v
选项,这使每个dependency节点下的artifactId节点和version节点成对输出。而xmlstarlet sel -C -t -v "//dependency/artifactId" -o " " -v "//dependency/version" -n pom2.xml
的输出(这里没执行)则显示是对整个文档先输出所有的”//dependency/artifactId”,再输出所有的version。
命名空间
前面提到pom2.xml是将pom.xml里的xmlns和xsi属性删除后的结果,上面的例子如果在pom.xml上执行都是没有结果的。这是因为xmlstarlet对xml的命名空间的识别的原因。pom.xml里的project节点声明了xmlns命名空间属性,要对它按xpath进行选择,要么把命名空间属性都删掉,像上面做的那样,要么在xpath里都指定命名空间。
xmlstarlet提供字符_
代表默认命名空间。比如将上面的一行输出artifactId和version的例子改写为xmlstarlet sel -t -m "//_:dependency" -v "_:artifactId" -o " " -v "_:version" -n pom.xml
这样就可以处理pom.xml了。
xmlstarlet还提供了-N
选项为命名空间进行命名。比如pom.xml里有两个命名空间,xmlstarlet可以写成:xmlstarlet sel -N d="http://maven.apache.org/POM/4.0.0" -N x="http://www.w3.org/2001/XMLSchema-instance" -t -m "//d:dependency" -v "d:artifactId" -o " " -v "d:version" -n pom.xml
这里d对应maven,x对应XMLSchema-instance。
编辑xml节点
xmlstarlet ed命令是对xml进行编辑的命令。本身很简单。
将dom4j的version从1.6.1与为1.7.1:xmlstarlet ed -u "//dependency[artifactId='dom4j']/version" -v "1.7.1" pom2.xml
虽然复杂的逻辑最终还是需要靠写代码,但是xmlstarlet还是节省了大量工作量。