使用XSD进行批量数据导入时生成的XML数据有效性这样的功能已经不是第一次做了,之前做的时候都没有碰到什么问题,这些天在开发中遇到了一个很头痛的问题就是无论XSD文件规则怎么写,验证都是通过的。
下面是具体的代码:
C#验证部分:
/// <summary> /// 对已转换成映射XML文件使用指定架构文件进行验证 /// </summary> /// <param name="mappingXmlFile">映射XML文件</param> /// <param name="schemaFile">架构文件</param> /// <returns>返回空字符串表示验证成功,否则返回错误信息</returns> public string ValidateMappingXMLFile(string mappingXmlFile, string schemaFile) { string namespaceUrl = "http://tempuri.org/MsisdnSchema.xsd"; XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; settings.Schemas.Add(namespaceUrl, schemaFile); settings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(settings_ValidationEventHandler); sb = new StringBuilder(); XmlReader reader = XmlReader.Create(mappingXmlFile, settings); try { reader.MoveToContent(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Document && reader.NamespaceURI != namespaceUrl) { return "Data does not match the specifications!"; } } } catch (XmlException ex) { sb.AppendFormat(ex.Message + "\n"); } finally { reader.Close(); } if (String.IsNullOrEmpty(sb.ToString())) { return string.Empty; } else { return "Validation Faild,Please check the validity of the data:" + sb.ToString(); } } public void settings_ValidationEventHandler(object sender, System.Xml.Schema.ValidationEventArgs e) { sb.Append(e.Message + "\n"); }
XML数据:
1 <?xml version="1.0" encoding="utf-8"?> 2 <MSISDN> 3 <List> 4 <BATCH_IMPORT_ID>6adbca51-c55f-4022-bcc0-84b209a78a38</BATCH_IMPORT_ID> 5 <BATCH_NO>20131027172271517</BATCH_NO> 6 <PORT_IN_MSISDN>31632000000</PORT_IN_MSISDN> 7 <CUSTOMER_TYPE>Business</CUSTOMER_TYPE> 8 <ID_TYPE>Passport</ID_TYPE> 9 <ID_NUMBER>1234567</ID_NUMBER> 10 <NATIONALITY>Netherlands</NATIONALITY> 11 <DAY_OF_BIRTH>2013-10-27</DAY_OF_BIRTH> 12 <COUNTRY_ID>Netherlands</COUNTRY_ID> 13 <LANGUAGE>Dutch - The Netherlands</LANGUAGE> 14 <COMPANY>ET.</COMPANY> 15 <STATUS_ID>Active</STATUS_ID> 16 <TITLE_ID>Mr.</TITLE_ID> 17 <FIRST_NAME>Mark</FIRST_NAME> 18 <MIDDLE_NAME> 19 </MIDDLE_NAME> 20 <LAST_NAME>Mulder</LAST_NAME> 21 <EMAIL>654645</EMAIL> 22 <ADDRESS>Schipholboulevard</ADDRESS> 23 <HOUSE_NO>249</HOUSE_NO> 24 <HOUSE_EXTENTION> 25 </HOUSE_EXTENTION> 26 <ZIP_CODE>4324</ZIP_CODE> 27 <CITY>Schipholboulevard</CITY> 28 <PACKAGE_NAME>88 mobile prepaid 2.5.0</PACKAGE_NAME> 29 <BILLING_EMAIL>martin.mulder@elephanttalk.com</BILLING_EMAIL> 30 <CUSTOMER_ID_DONOR>56346546</CUSTOMER_ID_DONOR> 31 <WISHDATE_PORTING>2013-10-27</WISHDATE_PORTING> 32 <NETWORK_OPERATOR>BEN</NETWORK_OPERATOR> 33 <SERVICE_PROVIDER>Atlantic Telecom</SERVICE_PROVIDER> 34 </List> 35 </MSISDN>
XSD验证架构
1 <?xml version="1.0" encoding="utf-8"?> 2 <xs:schema 3 id="MSISDNSchema" 4 targetNamespace="http://tempuri.org/MsisdnSchema.xsd" 5 elementFormDefault="qualified" 6 attributeFormDefault="unqualified" 7 xmlns="http://tempuri.org/MsisdnSchema.xsd" 8 xmlns:mstns="http://tempuri.org/MsisdnSchema.xsd" 9 xmlns:xs="http://www.w3.org/2001/XMLSchema"> 10 <xs:element name="MSISDN"> 11 <xs:complexType> 12 <xs:sequence> 13 <xs:element maxOccurs="unbounded" name="List"> 14 <xs:complexType> 15 <xs:sequence> 16 <xs:element name="BATCH_IMPORT_ID" minOccurs="0"> 17 <xs:simpleType> 18 <xs:restriction base="xs:string"> 19 <xs:maxLength value="36"/> 20 </xs:restriction> 21 </xs:simpleType> 22 </xs:element> 23 <xs:element name="BATCH_NO" minOccurs="0"> 24 <xs:simpleType> 25 <xs:restriction base="xs:string"> 26 <xs:maxLength value="50"/> 27 </xs:restriction> 28 </xs:simpleType> 29 </xs:element> 30 <xs:element name="PORT_IN_MSISDN"> 31 <xs:simpleType> 32 <xs:restriction base="xs:string"> 33 <xs:maxLength value="50"/> 34 </xs:restriction> 35 </xs:simpleType> 36 </xs:element> 37 <xs:element name="CUSTOMER_TYPE" minOccurs="0" default="Business"> 38 <xs:simpleType> 39 <xs:restriction base="xs:string"> 40 <xs:maxLength value="50"/> 41 </xs:restriction> 42 </xs:simpleType> 43 </xs:element> 44 <xs:element name="ID_TYPE" minOccurs="0" default="Passport"> 45 <xs:simpleType> 46 <xs:restriction base="xs:string"> 47 <xs:maxLength value="50"/> 48 </xs:restriction> 49 </xs:simpleType> 50 </xs:element> 51 <xs:element name="ID_NUMBER" default="1234567"> 52 <xs:simpleType> 53 <xs:restriction base="xs:string"> 54 <xs:maxLength value="20"/> 55 </xs:restriction> 56 </xs:simpleType> 57 </xs:element> 58 <xs:element name="NATIONALITY" minOccurs="0" default="Netherlands"> 59 <xs:simpleType> 60 <xs:restriction base="xs:string"> 61 <xs:maxLength value="20"/> 62 </xs:restriction> 63 </xs:simpleType> 64 </xs:element> 65 <xs:element name="DAY_OF_BIRTH" minOccurs="0"> 66 <xs:simpleType> 67 <xs:restriction base="xs:date"> 68 </xs:restriction> 69 </xs:simpleType> 70 </xs:element> 71 <xs:element name="COUNTRY_ID" minOccurs="0" default="Netherlands"> 72 <xs:simpleType> 73 <xs:restriction base="xs:string"> 74 <xs:maxLength value="50"/> 75 </xs:restriction> 76 </xs:simpleType> 77 </xs:element> 78 <xs:element name="LANGUAGE" minOccurs="0" default="Netherlands"> 79 <xs:simpleType> 80 <xs:restriction base="xs:string"> 81 <xs:maxLength value="50"/> 82 </xs:restriction> 83 </xs:simpleType> 84 </xs:element> 85 <xs:element name="COMPANY" minOccurs="0" fixed="ET."> 86 <xs:simpleType> 87 <xs:restriction base="xs:string"> 88 <xs:maxLength value="100"/> 89 </xs:restriction> 90 </xs:simpleType> 91 </xs:element> 92 <xs:element name="STATUS_ID" minOccurs="0" fixed="Active"> 93 <xs:simpleType> 94 <xs:restriction base="xs:string"> 95 <xs:maxLength value="20"/> 96 </xs:restriction> 97 </xs:simpleType> 98 </xs:element> 99 <xs:element name="TITLE_ID" minOccurs="0"> 100 <xs:simpleType> 101 <xs:restriction base="xs:string"> 102 <xs:maxLength value="20"/> 103 </xs:restriction> 104 </xs:simpleType> 105 </xs:element> 106 <xs:element name="FIRST_NAME" minOccurs="0"> 107 <xs:simpleType> 108 <xs:restriction base="xs:string"> 109 <xs:maxLength value="100"/> 110 </xs:restriction> 111 </xs:simpleType> 112 </xs:element> 113 <xs:element name="MIDDLE_NAME" minOccurs="0"> 114 <xs:simpleType> 115 <xs:restriction base="xs:string"> 116 <xs:maxLength value="100"/> 117 </xs:restriction> 118 </xs:simpleType> 119 </xs:element> 120 <xs:element name="LAST_NAME" minOccurs="0"> 121 <xs:simpleType> 122 <xs:restriction base="xs:string"> 123 <xs:maxLength value="100"/> 124 </xs:restriction> 125 </xs:simpleType> 126 </xs:element> 127 <xs:element name="EMAIL" minOccurs="0"> 128 <xs:simpleType> 129 <xs:restriction base="xs:string"> 130 <xs:maxLength value="100"/> 131 <xs:pattern value="([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)"/> 132 </xs:restriction> 133 </xs:simpleType> 134 </xs:element> 135 <xs:element name="ADDRESS" minOccurs="0"> 136 <xs:simpleType> 137 <xs:restriction base="xs:string"> 138 <xs:maxLength value="100"/> 139 </xs:restriction> 140 </xs:simpleType> 141 </xs:element> 142 <xs:element name="HOUSE_NO" minOccurs="0"> 143 <xs:simpleType> 144 <xs:restriction base="xs:string"> 145 <xs:maxLength value="25"/> 146 </xs:restriction> 147 </xs:simpleType> 148 </xs:element> 149 <xs:element name="HOUSE_EXTENTION" minOccurs="0"> 150 <xs:simpleType> 151 <xs:restriction base="xs:string"> 152 <xs:maxLength value="100"/> 153 </xs:restriction> 154 </xs:simpleType> 155 </xs:element> 156 <xs:element name="ZIP_CODE" minOccurs="0"> 157 <xs:simpleType> 158 <xs:restriction base="xs:string"> 159 <xs:maxLength value="25"/> 160 </xs:restriction> 161 </xs:simpleType> 162 </xs:element> 163 <xs:element name="CITY" minOccurs="0"> 164 <xs:simpleType> 165 <xs:restriction base="xs:string"> 166 <xs:maxLength value="100"/> 167 </xs:restriction> 168 </xs:simpleType> 169 </xs:element> 170 <xs:element name="PACKAGE_NAME" minOccurs="0"> 171 <xs:simpleType> 172 <xs:restriction base="xs:string"> 173 <xs:maxLength value="50"/> 174 </xs:restriction> 175 </xs:simpleType> 176 </xs:element> 177 <xs:element name="BILLING_EMAIL" minOccurs="0"> 178 <xs:simpleType> 179 <xs:restriction base="xs:string"> 180 <xs:maxLength value="100"/> 181 </xs:restriction> 182 </xs:simpleType> 183 </xs:element> 184 <xs:element name="CUSTOMER_ID_DONOR" minOccurs="0"> 185 <xs:simpleType> 186 <xs:restriction base="xs:string"> 187 <xs:maxLength value="100"/> 188 </xs:restriction> 189 </xs:simpleType> 190 </xs:element> 191 <xs:element name="WISHDATE_PORTING" minOccurs="0"> 192 <xs:simpleType> 193 <xs:restriction base="xs:date"> 194 </xs:restriction> 195 </xs:simpleType> 196 </xs:element> 197 <xs:element name="NETWORK_OPERATOR" minOccurs="0"> 198 <xs:simpleType> 199 <xs:restriction base="xs:string"> 200 <xs:maxLength value="10"/> 201 </xs:restriction> 202 </xs:simpleType> 203 </xs:element> 204 <xs:element name="SERVICE_PROVIDER" minOccurs="0"> 205 <xs:simpleType> 206 <xs:restriction base="xs:string"> 207 <xs:maxLength value="50"/> 208 </xs:restriction> 209 </xs:simpleType> 210 </xs:element> 211 </xs:sequence> 212 </xs:complexType> 213 </xs:element> 214 </xs:sequence> 215 </xs:complexType> 216 </xs:element> 217 </xs:schema>
可见,<EMAIL>654645</EMAIL>项是一个不符合Email正则表达式验证的Email地址,可是执行的结果依然是没有进行验证。
在园子里的另一篇文章http://q.cnblogs.com/q/38157/ 给了我启发,我把XML数据的对XSD命名空间的引用,<MSISDN xmlns="http://tempuri.org/MsisdnSchema.xsd" >
发现这次验证是可以正常进行的,说明问题出在了XML数据上。
“XmlReader 在执行验证的时候不光需要xsd文件,还需要xml文件显示的引用xsd的NameSpaces,这样才就可以去匹配验证每个元素。”果然如帖子中说的一样。
可这样格式的XML数据,在进行校验过后,要转换成Dataset进行再次处理会比较麻烦,需要先获取XML架构再取数据,那么能不能不修改XML数据就验证成功呢?
我对代码和XSD数据进行了如下修改:
xsd里面
去掉
targetNamespace="http://tempuri.org/MsisdnSchema.xsd"
代码里面(写出的部分为替换注释掉部分的代码)
//string namespaceUrl = "http://tempuri.org/MsisdnSchema.xsd"; //settings.Schemas.Add(namespaceUrl, schemaFile); settings.Schemas.Add(null, schemaFile); //if (reader.NodeType == XmlNodeType.Document && reader.NamespaceURI != namespaceUrl) if (reader.NodeType == XmlNodeType.Document && reader.NamespaceURI !=null)
再运行程序,代码就通过了,验证可以正常运行。
可能有不少同学在学习XSD验证XML的时候,会参考园子里的一篇博客
http://www.cnblogs.com/chenxizhang/archive/2009/06/19/1507121.html
我想指出的是,
如果XML数据文件没有引用任何XSD的命名空间,那么在代码中,是不需要设置XmlReader的namespaceUrl的,并且XSD中也不需要设置targetNamespace项的值,否则验证是不会进行的,验证结果永远都是成功。