案例十5、格式化输出xml文件

在工做中咱们多多少少都接触过xml文件,它的格式很是有规律性,但读起来由于有太多的标签(<>),不能一目了然,就好比下面一段配置:bash

<configuration>
     <artifactItems>
          <artifactItem>
              <groupId>zzz</groupId>
              <artifactld>aaa</artifactld>
          </artifactItem>
          <artifactItem>
              <groupId>xxx</groupId>
              <artifactld>yyy</artifactld>
          </artifactItem>
</artifactItems>

本案例的需求是从上面的XML文本中提取groupId和artifactld,并输出为以下格式:ide

artifactItem:groupId:zzz
artifactItem:artifactld:aaa
artifactItem:groupId:xxx
artifactItem:artifactld:yyy


知识点一:关于XML的小常识函数

XML(Extensible Markup Language),中文叫作:可扩展标记语言。XML和HTML很像,都是一种标记语言。XML主要用来传送以及携带数据信息,而不是用来展现的,因此读起来就有点障碍。测试


有很多服务的配置文件就是一个XML文本,在XML文本中定义对应的配置,就好比本案例中示例文本就是一个配置文件。XML的做用主要在于存储数据,它以纯文本格式进行存储,所以提供了一种独立于软件和硬件的数据存储方法。这让建立不一样的应用程序能够共享的数据变得更加容易。因为XML文本的格式是固定的,不管是Windows、Linux或者MAC等其余操做系统,均可以识别,因此它的兼容性很好。spa


有一点,咱们必需要知道,就是XML是一种不做为的标记语言,即,它不像HTML须要被解析、执行而后展现漂亮的网页,它存在的意义仅仅是结构化、存储以及传输信息。操作系统


知识点二:截取文档中两个关键词中间的行xml

需求是,把文本中包含abc和123中间的部分打印出来,假设abc在123上面。若是使用sed,一条命令便可实现:文档

# sed -n '/abc/,/123/p' 1.txt

不过这样依然有abc和123的行,要想去掉他们,也很简单:get

# sed -n '/abc/,/123/p' 1.txt |sed '/abc/d;/123/d'

若是文本中有多个abc和123,则会同时把全部符合条件的行所有打印出来,下面提供一个比较笨的土方法,帮助练习逻辑思惟能力。it

mysed.sh

#!/bin/bash
#先获取abc和123所在行的行号
egrep -n 'abc|123' 1.txt |awk -F ':' '{print $1}' > /tmp/line_number.txt

#计算一共有多少包含abc和123的行
n=`wc -l /tmp/line_number.txt|awk '{print $1}'`

#计算一共有多少对abc和123
n2=$[$n/2]

for i in `seq 1 $n2`
do
    #每次循环都要处理两行,第一次是1,2,第二次是3,4,依此类推
    m1=$[$i*2-1]
    m2=$[$i*2]

    #每次遍历都要获取abc和123的行号
    nu1=`sed -n "$m1"p /tmp/line_number.txt`
    nu2=`sed -n "$m2"p /tmp/line_number.txt`

    #获取abc下面一行的行号
    nu3=$[$nu1+1]

     #获取123上面一行的行号
    nu4=$[$nu2-1]
    
    #用sed把abc和123中间的行打印出来
    sed -n "$nu3,$nu4"p 1.txt

    #便于分辨,添加分隔行符号
    echo "============="
done

提供一个测试的文本1.txt,内容以下:

alskdfkjlasldkjfabalskdjflkajsd
asldkfjjk232k3jlk2
alskk2lklkkabclaksdj
skjjfk23kjalf09wlkjlah lkaswlekjl9
aksjdf
123asd232323
aaaaaaaaaa
222222222222222222
abcabc12121212
fa2klj
slkj32k3j
22233232123
bbbbbbb
ddddddddddd

用sed处理,结果是:

# sed -n '/abc/,/123/p' 1.txt |sed '/abc/d;/123/d'
skjjfk23kjalf09wlkjlah lkaswlekjl9
aksjdf
fa2klj
slkj32k3j

用mysed.sh处理,结果是:

# sh mysed.sh 
skjjfk23kjalf09wlkjlah lkaswlekjl9
aksjdf
=============
fa2klj
slkj32k3j
=============


案例分析

1)首先要找到<artifactItem>和</artifactItem>中间的数据段,针对这部分数据进行分析

2)能够找到XML文档中包含<artifactItem>和</artifactItem>的行的行号,而后使用sed把这部份内容截取出来

3)处理截取出来的数据段,使用sed、awk截取关键词以及对应的值


本案例参考脚本

#!/bin/bash
#按要求输出XML内容,本脚本定制性较强,不可通用
#做者:
#日期:

#假设要处理的XML文档名字为test.xml
#获取和所在的行号
grep -n 'artifactItem>' test.xml |awk '{print $1}' |sed 's/://' > /tmp/line_number.txt

#计算和的行一共有多少行
n=`wc -l /tmp/line_number.txt|awk '{print $1}'`

#定义获取关键词和其值的函数
get_value(){
    #$1和$2为函数的两个参数,即下一行和上一行的行号(这个操做在下面)
    #截取出和中间的内容,而后获取关键词(如groupId)和其对应的值,写入/tmp/value.txt
    sed -n "$1,$2"p test.xml|awk -F '<' '{print $2}'|awk -F '>' '{print $1,$2}' > /tmp/value.txt

    #遍历整个/tmp/value.txt文档
    cat /tmp/value.txt|while read line
    do
        #x为关键词,如groupId
        #y为关键词的值
        x=`echo $line|awk '{print $1}'`
        y=`echo $line|awk '{print $2}'`
        echo artifactItem:$x:$y
    done
}

#因为/tmp/line_number.txt是成对出现的,n2为一共多少对
n2=$[$n/2]

#针对每一对,打印关键词和对应的值
for j in `seq 1 $n2`
do
    #每次循环都要处理两行,第一次是1,2,第二次是3,4,依此类推
    m1=$[$j*2-1]
    m2=$[$j*2]

    #每次遍历都要获取和的行号
    nu1=`sed -n "$m1"p /tmp/line_number.txt`
    nu2=`sed -n "$m2"p /tmp/line_number.txt`

    #获取下面一行的行号
    nu3=$[$nu1+1]

     #获取上面一行的行号
    nu4=$[$nu2-1]

    get_value $nu3 $nu4
done
相关文章
相关标签/搜索