使用shell工具(如grep,awk或sed)解析xml
问题描述:
我有以下xml解析并根据标记的值提取标记的值。仅当type =='hosted'时才提取。我想使用像grep,sed和awk这样的bash工具进行提取。在没有条件的情况下提取单个标签值是我之前完成的,而不是条件。我可以很容易地使用Python或我知道的任何其他编程语言来完成它。但是如果在shell脚本中完成,这将是理想的。使用shell工具(如grep,awk或sed)解析xml
...
<repositories-item>
<name>hosted-npm</name>
<type>hosted</type>
</repositories-item>
<repositories-item>
<name>proxied-npm</name>
<type>proxied</type>
</repositories-item>
...
答
缺乏XML专用工具
awk
使用封闭的标签来定义记录抢救定界符
$ awk -v RS='</?repositories-item>' '/<type>hosted<\/type>/' file
<name>hosted-npm</name>
<type>hosted</type>
注意,这需要多焦RS这GNU awk
支持。
可以对匹配更多的控制和输出
$ awk -v RS='</?repositories-item>' -F'[<>]' '
{delete a;
for(i=2;i<=NF;i+=4) a[$i]=$(i+1);
if(a["type"]=="hosted") print a["name"] }' file
hosted-npm
答
xmlstarlet是一个命令行工具包的XML可以表达复杂的XSLT模板作为命令行开关的短序列。
假设我们正在提供一个良好的XML文档repos.xml
<repositories>
<repositories-item>
<name>hosted-npm</name>
<type>hosted</type>
</repositories-item>
<repositories-item>
<name>proxied-npm</name>
<type>proxied</type>
</repositories-item>
</repositories>
如果通过XMLStarlet过滤器使用以下开关
$ cat repos.xml | xmlstarlet sel -t -m '//repositories-item' \
-i 'type="hosted"' -v 'name' -n
运行它,你会得到输出
的一行 让我们看看XMLStarlet命令li东北。
- 我们经营与
sel
开关指定的选择模式的命令 - 我们指定与
-t
开关 - 我们限制选择模板解析器与该
-m
swicth 指定的
- 我们只选择这些元素作为
type
元素的“托管”值-i
开关 - 我们打印出
name
元素的值,使用-v
开关指定。 - 在每行输出之后,我们打印一个由
-n
开关指定的换行符。
//repositories-item
模板
<repositories-item>
元素
这里是通过XMLStarlet
产生的等效XSLT<?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="//repositories-item">
<xsl:choose>
<xsl:when test="type="hosted"">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name"/>
</xsl:call-template>
<xsl:value-of select="' '"/>
</xsl:when>
</xsl:choose>
</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>
每查尔斯达菲建议它值得注意的是,此XSLT规范可以使用XMLStarlet的-C
选项生成:
xmlstarlet sel -C -t -m '//repositories-item' \
-i 'type="hosted"' -v 'name' -n > hosted-repos.xslt
这个生成的XSLT规范可以直接使用xsltproc
作为
cat repos.xml | xsltproc hosted-repos.xslt -
+2
可能值得向OP展示如何使用'xsltproc'来应用该XSLT,以确保他们明白他们可以在服务器上使用此解决方案没有安装XMLStarlet。 –
我强烈建议您使用XML工具来处理XML(在Python等中)。特别是,您可以考虑编写一个合适的XSLT样式表,并使用脚本中的'xsltproc'命令将样式表应用于XML输入。 –
查看[xmlstarlet](http://xmlstar.sourceforge.net/) –