本人在工作中遇到一個需要用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文件方法的話希望大家多多指點,十分感謝!