通过shell解析xml文件
本人在工作中遇到一个需要用shell文件定期解析xml文件取出其中标签中的值的工作。
在尝试了多种方法以后整理出了一个相对于比较简便的解析方法,仅供参考。
首先我们需要知道xml文件的结构,xml文件由文件头与文件体组成。文件体由根节点与子节点构成。
文件头顾名思义处于文件的开始部分,一般标明了xml文件的版本编码等信息。例如以下例子中的第一行:
<?xml version="1.0" encoding="utf-8"?>
根节点处于文件体的开始与结束,例如以下例子中的:<urlset></urlset>
子节点是相对的,比如说<url>是根节点<urlset>的子节点,<ID>是<url>的子节点。
例如我们现在需要解析xml文件中<url>标签的内容,也就是说要解析ID、姓名、电话、身份证号、微信号、申请时间、审批状态、审批时间这几个标签的值。
具体内容如下:
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<ID>AE0530A78C913635A</ID>
<姓名>JOK</姓名>
<电话>1325314002</电话>
<身份证号>1234567890</身份证号>
<微信号>dh1562</微信号>
<申请时间>2018-09-02</申请时间>
<审批状态>1</审批状态>
<审批时间>2018-09-02</审批时间>
</url>
<url>
<ID>01053609F780A5FF6</ID>
<姓名>TOM</姓名>
<电话>1803270891</电话>
<身份证号>1234567890</身份证号>
<微信号>ch1234</微信号>
<申请时间>2018-09-02</申请时间>
<审批状态>0</审批状态>
<审批时间>null</审批时间>
</url>
</urlset>
因为有多个url标签存在,所以本人解析xml文件的思路是首先设定分隔符将xml文件内容分隔成一段一段的只包含一对<url></url>标签以及子标签的内容。然后将该内容重定向到一个子文件,再从子件中设定分隔符来读取具体想要的值。
具体步骤如下:
1.设定分隔符将xml文件内容分隔成一段一段的只包含一对<url></url>标签以及子标签的内容:
text=`awk -v RS="</url>" "NR==$m{print}" $filename`
awk的具体功能大家可以在网上查阅资料了解,应为涉及到循环所以{print}前面的参数是一个变量。
2.然后将该内容重定向到一个子文件:
echo $text >123.txt
3.再从子件中设定分隔符来读取具体想要的值,以取<ID><ID>中的值为例:
ID=`awk -v RS="</*ID>" 'NR==2{print}' 123.txt`
具体代码如下:
#!/bin/sh
. ~/.profile
#本地文件存放地址
filepath=/testbk/ws
#取日期
vdate=$(date +%Y%m%d)
echo $vdate
#文件名称
filename="REGISTERINFO_"$vdate".xml"
#文件尾包含字符串(退出循环的判断条件)
endtxt="</urlset>"
#进入本地文件存放地址
cd $filepath
#取第几段内容的参数
m=1
#定义一个死循环
while :
do
#取xml文件第m段的内同
text=`awk -v RS="</url>" "NR==$m{print}" $filename`
#将该内容重定向到特定文件
echo $text >123.txt
#如果本次循环的域内容不包含文件尾,则解析该内容
if [ `grep -c "$endtxt" 123.txt` -eq '0' ]; then
ID=`awk -v RS="</*ID>" 'NR==2{print}' 123.txt`
NAME=`awk -v RS="</*姓名>" 'NR==2{print}' 123.txt`
TEL=`awk -v RS="</*电话>" 'NR==2{print}' 123.txt`
IDCARDNUM=`awk -v RS="</*身份证号>" 'NR==2{print}' 123.txt`
WCHAT=`awk -v RS="</*微信号>" 'NR==2{print}' 123.txt`
APPLYTIME=`awk -v RS="</*申请时间>" 'NR==2{print}' 123.txt`
APPSTATUS=`awk -v RS="</*审批状态>" 'NR==2{print}' 123.txt`
APPTIME=`awk -v RS="</*审批时间>" 'NR==2{print}' 123.txt`
else
echo "文件读取结束"
#退出死循环
break
fi
m=`expr $m + 1`
done
过程会是这样子,xml文件内容会被分解为三部分,分别是:
一:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<ID>AE0530A78C913635A</ID>
<姓名>JOK</姓名>
<电话>1325314002</电话>
<身份证号>1234567890</身份证号>
<微信号>dh1562</微信号>
<申请时间>2018-09-02</申请时间>
<审批状态>1</审批状态>
<审批时间>2018-09-02</审批时间>
</url>
二:
<url>
<ID>01053609F780A5FF6</ID>
<姓名>TOM</姓名>
<电话>1803270891</电话>
<身份证号>1234567890</身份证号>
<微信号>ch1234</微信号>
<申请时间>2018-09-02</申请时间>
<审批状态>0</审批状态>
<审批时间>null</审批时间>
</url>
三:
</urlset>
第一、二次循环会将内容重定向到123.txt中,然后在解析123.txt文件的内容,取出想要的节点中的值。
第三次循环取到的值包含根节点的结尾节点</url>,if判断结构为false,所以会走else分支,该分支中有break退出循环。
本人小白一枚,对shell的了解也不是很深入,如果有更加简便的解析xml文件方法的话希望大家多多指点,十分感谢!