xml解析

  最近的一个项目,调用第三方的接口来获取数据并呈现,第三方接口收发的数据采用xml格式,返回的xml有点让人蛋疼,可读性差,语义破碎。这使得本人这边的项目使用起来有点费劲,之前项目组一个成员,根据接收的报文示例,采用绝对定位的方式读取其中的数据,非常不健壮,只要报文中元素标签的位置发生变化,获取的结果就不对了。之前项目为了赶进度,就在原来的代码基础上加了点封装,基本满足生产环境的要求。但是仅仅两个方法就一百多行代码,显然还有待优化。故利用假期闲暇时段做了点优化,代码量减少了一半,看着舒服多了。

  具体问题如下:

返回的报文有两种类型:

  (1)用户基本信息:

  

<?xml version="1.0" ?>
<response>
<meta>
<reqserialno>GJ07L20151223150941707527</reqserialno>
<channeltype>016</channeltype>
</meta>
<data>
<list>
<info>
<orderby />
<pages>1</pages>
<page>1</page>
<total>1</total>
</info>
<cols>
<custacno />
<custname />
<paperkind />
<paperid />
<corpacno />
<accubankid />
<bankname />
<corpname />
<cardflag />
<monthinco />
<averinco />
<isspeperc />
<custperc />
<corpperc />
<isalloperc />
<alloperc />
<alloamt />
<accuamt />
<sumamt />
<bal />
<custacstat />
<custtrusstat />
<operdate />
<bankid />
<operid />
<agentcorpno />
<drawcardflag />
<cardstat />
<lastsavemonth />
<channeltype />
<custid />
<accucardno />
<orderno />
<custdept />
<natisign2 />
<bindbanktype />
<bankcardno />
</cols>
<rows>
<row id="1">
<c>0961838227</c>
<c>韩**</c>
<c>A</c>
<c>420803198204045129</c>
<c>1201043768</c>
<c>010206</c>
<c>建行干将支行(大厅)</c>
<c>**市住房公积金管理中心</c>
<c>1</c>
<c>8450</c>
<c>8450</c>
<c />
<c>12</c>
<c>12</c>
<c>1</c>
<c>18</c>
<c>1521</c>
<c>2028</c>
<c>3549</c>
<c>9702.23</c>
<c>200</c>
<c>230</c>
<c>20120926</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>1</c>
<c>001</c>
<c>201511</c>
<c>002</c>
<c>A4208031982040451290</c>
<c>09618382271</c>
<c />
<c />
<c>156</c>
<c>014</c>
<c>6214619999025685774</c>
</row>
</rows>
</list>
</data>
</response>

  (2) 用户记录信息: 

<?xml version="1.0" ?>
<response>
<meta>
<reqserialno>GJ08L12015122315121134560494</reqserialno>
<channeltype>016</channeltype>
</meta>
<data>
<list>
<info>
<orderby />
<pages>6</pages>
<page>1</page>
<total>53</total>
</info>
<cols>
<acbooknum />
<corpacno />
<custacno />
<custname />
<busidetailtype />
<acculistid />
<amt />
<inte />
<bal />
<fixedsavebal />
<demandsavebal />
<note />
<acdate />
<bankid />
<acid />
<cancelacbooknum />
<savemonth />
<flag />
<bankname />
<r />
</cols>
<rows>
<row id="1">
<c>2000000</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>103</c>
<c>12010437682038</c>
<c>6183</c>
<c>0</c>
<c>6183</c>
<c>0</c>
<c>6183</c>
<c>201207201209</c>
<c>20120927</c>
<c>010206</c>
<c>010206017</c>
<c />
<c />
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>1</c>
</row>
<row id="2">
<c>2000001</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682040</c>
<c>2061</c>
<c>0</c>
<c>8244</c>
<c>0</c>
<c>8244</c>
<c />
<c>20121010</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201210</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>2</c>
</row>
<row id="3">
<c>2000002</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682042</c>
<c>2061</c>
<c>0</c>
<c>10305</c>
<c>0</c>
<c>10305</c>
<c />
<c>20121112</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201211</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>3</c>
</row>
<row id="4">
<c>2000003</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682045</c>
<c>2061</c>
<c>0</c>
<c>12366</c>
<c>0</c>
<c>12366</c>
<c />
<c>20121210</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201212</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>4</c>
</row>
<row id="5">
<c>2000004</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682046</c>
<c>2061</c>
<c>0</c>
<c>14427</c>
<c>0</c>
<c>14427</c>
<c />
<c>20130110</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201301</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>5</c>
</row>
<row id="6">
<c>2000005</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682047</c>
<c>2061</c>
<c>0</c>
<c>16488</c>
<c>0</c>
<c>16488</c>
<c />
<c>20130207</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201302</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>6</c>
</row>
<row id="7">
<c>2000006</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682048</c>
<c>2061</c>
<c>0</c>
<c>18549</c>
<c>0</c>
<c>18549</c>
<c />
<c>20130311</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201303</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>7</c>
</row>
<row id="8">
<c>2000007</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682050</c>
<c>2061</c>
<c>0</c>
<c>20610</c>
<c>0</c>
<c>20610</c>
<c />
<c>20130410</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201304</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>8</c>
</row>
<row id="9">
<c>2000008</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>101</c>
<c>12010437682051</c>
<c>2061</c>
<c>0</c>
<c>22671</c>
<c>0</c>
<c>22671</c>
<c />
<c>20130510</c>
<c>010203</c>
<c>010203000</c>
<c />
<c>201305</c>
<c>收入</c>
<c>建行干将支行(大厅)</c>
<c>9</c>
</row>
<row id="10">
<c>2000009</c>
<c>1201043768</c>
<c>0961838227</c>
<c>韩**</c>
<c>106</c>
<c>09618382272000</c>
<c>9900</c>
<c>0</c>
<c>12771</c>
<c>0</c>
<c>12771</c>
<c />
<c>20130513</c>
<c>010110</c>
<c>010110002</c>
<c />
<c />
<c>支出</c>
<c>建行干将支行(大厅)</c>
<c>10</c>
</row>
</rows>
</list>
</data>
</response>

 

  项目的要求是基本信息用一页显示,记录信息用列表显示,且记录信息可能有多条,需要进行分页处理。基本信息的字段名称是cols元素的子元素,以其对应的名称做为标签名,基本信息的值在row元素内,标签名都是c,且数量和顺序和cols的子元素一一对应。记录信息的字段名称是cols的子元素,每次返回的记录有10条,在rows元素内,每条记录对应其一个子元素row,另外,每次报文中会返回3个重要参数:当前页码,总页数,记录总数,值分别在info元素的子元素<page></page>,<pages></pages>,<total></total>中。

我针对以上两种xml的解析方法:

 1 public class XmlConvertorByXPath
 2     {
 3         public static Hashtable Convertor1(string xml, string path1, string path2)
 4         {
 5             System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
 6             xmlDoc.LoadXml(xml);
 7             if (xmlDoc.SelectSingleNode(path1) == null) return null;
 8             var nodeList1 = xmlDoc.SelectSingleNode(path1).ChildNodes;
 9             var nodeList2 = xmlDoc.SelectSingleNode(path2).ChildNodes;
10             Hashtable hash = new Hashtable();
11             if (nodeList1.Count != nodeList2.Count)
12             {
13                 return null;
14             }
15             else
16             {
17                 for (int i = 0; i < nodeList1.Count; i++)
18                 {
19                     var key = nodeList1[i].Name;
20                     var value = !string.IsNullOrEmpty(nodeList2[i].InnerText) ? nodeList2[i].InnerText : "";
21                     hash.Add(key, value);
22                 }
23                 return hash;
24             }
25         }
26         public static List<Hashtable> Convertor2(string xml, string path1, string path2,string path3)
27         {
28             System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
29             xmlDoc.LoadXml(xml);            
30             if (xmlDoc.SelectSingleNode(path1) == null) return null;
31             XmlNodeList xmlNodeList = xmlDoc.SelectNodes(path2);
32             if (0 == xmlNodeList.Count) return null;
33             var nodeList1 = xmlDoc.SelectSingleNode(path1).ChildNodes;
34             var nodeList2 = xmlDoc.SelectSingleNode(path3).ChildNodes;
35             List<Hashtable> hashList = new List<Hashtable>();
36             for (int i = 0; i < xmlNodeList.Count; i++)
37             {
38                 Hashtable hash = new Hashtable();
39                 var nodes2 = xmlNodeList[i].ChildNodes;
40                 if (nodes2.Count != nodeList1.Count)
41                     continue;
42                 for (int j = 0; j < nodes2.Count; j++)
43                 {
44                     var key = nodeList1[j].Name;
45                     var value = !string.IsNullOrEmpty(nodes2[j].InnerText) ? nodes2[j].InnerText : "";
46                     hash.Add(key, value);
47                 }
48                 for (int k = 0; k < nodeList2.Count; k++) {
49                     var key = nodeList2[k].Name;
50                     var value = !string.IsNullOrEmpty(nodeList2[k].InnerText) ? nodeList2[k].InnerText : "";
51                     hash.Add(key,value);
52                 }
53                 hashList.Add(hash);
54             }
55             return hashList;
56         }
57     }

  目的很简单,就是将xml数据转换为可以按键取值的形式,当然前提是返回的字段名称不重复,且有一定的语义。希望对遇到类似问题的朋友有所帮助。

原文地址:https://www.cnblogs.com/Lightmen/p/5097462.html