diff --git a/xmlparser.sh b/xmlparser.sh
new file mode 100644
index 0000000..47abc76
--- /dev/null
+++ b/xmlparser.sh
@@ -0,0 +1,128 @@
+#!/usr/bin/env bash
+#0.
+#1.Only For Test
+#2.
+#3.
+#4.
+#Attribute=Attribute Name
+#VALUE=Attribute Value
+#ELEMENT=Element Name
+#CONTENT=Element Content
+
+#接受一个int层级参数,层级从0开始
+echo_tabs() {
+ local tabs="";
+ for((i = 0; i < $1; i++)); do
+ tabs=$tabs' ' #4个空格
+ done
+ echo -n "$tabs" #一定要加双引号
+}
+
+read_dom() {
+ #备份IFS
+ local oldIFS=$IFS
+
+ local IFS=\> #字段分割符改为>
+ read -d \< ENTITY CONTENT #read分隔符改为<
+ local ret=$?
+ local ELEMENT=''
+ #第一次执行时,第一个字符为<.
+ #所以read执行完毕,ENTITY和CONTENT都是空白符
+ if [[ $ENTITY =~ ^[[:space:]]*$ ]] && [[ $CONTENT =~ ^[[:space:]]*$ ]]; then
+ return $ret
+ fi
+
+ #第二次执行时,分为下面集中情况
+ #0.
+ #此时read结果为?xml version="1.0" encoding="utf-8"?
+ #CONTENT=若干空白符
+
+ #1.1785
+ #此时read结果为Size,所以ENTITY=Size,CONTENT='1785'
+ #第三次read结为/Size,所以ENTITY=/Size,CONTENT=若干空白符
+
+ #2.
+ #此时read结果为ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/",所以ENTITY=tListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/",CONTENT=同#1
+
+ #3.
+ #此时read结果为test/,所以ENTITY=test/,CONTENT=若干空白符
+
+ #4.
+ #此时read结果为test name="xyz" age="21"/,所以ENTITY=test name="xyz"/,CONTENT=若干空白符
+
+ #5.
+ #此时read结果为!--q1--,所以ENTITY=!--q1--,CONTENT=''
+
+ # ENTITY = ?xml version="1.0" encoding="utf-8"?
+ #解析xml声明,并非普通节点,闭合方式与节点不同
+ if [[ "$ENTITY" =~ ^\?xml[[:space:]]*(.*)\?$ ]]; then #使用正则去除问号和xml字符
+ ENTITY=''
+ ELEMENT='' #不是普通节点
+ ATTRIBUTES="${BASH_REMATCH[1]}" #获取声明中的属性
+ else #普通节点
+ ELEMENT=${ENTITY%% *} #获取节点名称,如果ENTITY中有空格,则第一个空格前面部分即为节点名称
+ ATTRIBUTES=${ENTITY#* } #获取节点所有属性,如果ENTITY中有空格,则第一个空格后面部分为所有属性(#2和#4,#4情况下,会多出/)
+ fi
+
+ if [[ "$ENTITY" = \!--*-- ]]; then #不检查注释(#5)
+ return 0
+ fi
+
+ if [[ "$ELEMENT" = /* ]]; then #节点末尾 #1第三步
+ tabCount=$[$tabCount - 1]
+ echo_tabs $tabCount
+ echo END ${ELEMENT#*/} #删除/
+ return 0
+ elif [[ "$ELEMENT" = */ ]] || [[ $ATTRIBUTES = */ ]]; then #3或#4
+ empty=true #节点没有子节点,也没有value(自身为闭合标签)
+ if [[ $ATTRIBUTES = */ ]]; then #如果是#4情况
+ ATTRIBUTES=${ATTRIBUTES%*/} #将末尾的/删除,提取所有属性
+ fi
+ echo_tabs $tabCount
+ echo -n ELEMENT=${ELEMENT%*/}' '
+ elif [ ! "$ELEMENT" = '' ]; then #第一次执行时,ENTITY和CONTENT都是空串
+ echo_tabs $tabCount
+ echo -n ELEMENT="$ELEMENT"' ' #输出节点名
+ tabCount=$[$tabCount + 1] #新节点
+ else
+ echo -n "XML declaration " #ELEMENT为空,不计算层级
+ fi
+
+ local empty=false #没有子节点,没有value
+ IFS=$oldIFS #属性之间由空白符分割,恢复IFS,IFS默认为空格/换行/制表符
+ local hasAttribute=false #节点是否有属性
+ for a in $ATTRIBUTES; do #循环所有属性
+ #echo ATTRIBUTES=$ATTRIBUTES ' -+-+-+- '
+ if [[ "$a" = *=* ]] #情况#2和#4
+ then
+ hasAttribute=true
+ ATTRIBUTE_NAME=${a%%=*} #提取属性名
+ ATTRIBUTE_VALUE=`tr -d '"' <<< ${a#*=}` #提取属性值并去掉双引号
+ echo -n ATTRIBUTE=$ATTRIBUTE_NAME VALUE=$ATTRIBUTE_VALUE' ' #输出属性名/属性值
+ fi
+ done
+
+ if [[ ! "$CONTENT" =~ ^[[:space:]]*$ ]]; then
+ echo -n CONTENT=$CONTENT
+ fi
+
+ if [ "$empty" = true ]; then
+ echo
+ echo_tabs $tabCount
+ echo -n END ${ELEMENT%/*} #删除/
+# echo -n ' (empty node)'
+ fi
+
+ echo
+ return $ret
+}
+
+read_xml() {
+ local tabCount=0 #用来格式化输出,计算节点层级
+ while read_dom; do
+ :
+ done < "$1"
+}
+
+read_xml "$1"