获取xml时,出现“(十六进制值 0x1F)是无效的字符之类Xml异常的解决办法
2009-06-06 13:58
423 查看
获取xml时,出现“(十六进制值0x1F)是无效的字符之类Xml异常的解决办法
2008-12-1910:44
最近做新闻采集器,需要获取很多站点的xml,加载个别站点经常出现“(十六进制值0x1F)是无效的字符”问题,百思不的其解。对于问题站点xml的处理,开始的思路是既然直接用XmlDocument对象的Load()方法不行,就用LoadXML(),用HttpWebRequest获取url读到流里再转为xml,中间可以加一些非有效字符的过滤处理,但仍然无效,仅仅解决了请求超时的问题... 问题搁置了1周后,终于在今天解决了。 其实很简单,只加一条语句就搞定了 XmlDocumentdoc=newXmlDocument(); doc.Normalize(); //摘要: //将此XmlNode下子树完全深度中的所有XmlText节点都转换成“正常”形式,在这种形式中只有标记(即标记、注释、处理指令、CDATA //节和实体引用)分隔XmlText节点,也就是说,没有相邻的XmlText节点。 以下是转一位仁兄的贴: 最近碰到一个问题,我的一个把数据库中记录的信息暴露出来的WebService调用时候出问题了。报下面的错误信息: System.InvalidOperationExceptionwasunhandled Message="XML文档(1,823)中有错误。" Source="System.Xml" Message="“”(十六进制值0x0E)是无效的字符。行1,位置823。" Source="System.Xml" 当这个错误发生时,WebService服务器端不会有任何错误,而调用这个WebService的客户端则会报上述错误。 是何原因导致的这个问题呢? 答案很简单,是WEBService暴露的XML文档中存在低序位非打印ASCII字符所致。 我们查看WebService返回的XML文档文档中,会有下面的XML文档节:其中的就是低序位ASCII字符。对应的字符如后: <Value>在神奇天地裏誰叱咤風雨</Value> 会导致这些问题的低序位非打印ASCII字符包含以下字符: #x0-#x8(ASCII0-8) #xB-#xC(ASCII11-12) #xE-#x1F(ASCII14-31) 下面就是一个简单演示这个问题的控制台程序, 为了简单起见,这里没有建立WebService,而是把一个类XML序列化存储到文件,然后再把这个文件反序列化读取出来: 其中的这个类的Value值中,放了一个低序位非打印ASCII字符。 执行这个控制台程序,就会报异常。“XML文档(3,12)中有错误。” usingSystem; usingSystem.Xml.Serialization; usingSystem.IO; usingSystem.Text; usingSystem.Globalization; namespaceTextSerialize { [Serializable] publicclassMyClass { publicstringValue{get;set;} } classProgram { staticvoidMain(string[]args) { stringfileName="d://1.txt"; MyClassc=newMyClass(); c.Value=string.Format("在神奇{0}天地裏誰叱咤風雨",Convert.ToChar(14)); SaveAsXML(c,fileName,Encoding.UTF8); objecto=ConvertFileToObject(fileName,typeof(MyClass),Encoding.UTF8); MyClassd=oasMyClass; if(d!=null)Console.WriteLine(d.Value); elseConsole.WriteLine("null"); Console.ReadLine(); } ///<summary> ///序列化 ///</summary> ///<paramname="objectToConvert"></param> ///<paramname="path"></param> ///<paramname="encoding"></param> publicstaticvoidSaveAsXML(objectobjectToConvert,stringpath,Encodingencoding) { if(objectToConvert!=null) { Typet=objectToConvert.GetType(); XmlSerializerser=newXmlSerializer(t); using(StreamWriterwriter=newStreamWriter(path,false,encoding)) { ser.Serialize(writer,objectToConvert); writer.Close(); } } } ///<summary> ///反序列化 ///</summary> ///<paramname="path"></param> ///<paramname="objectType"></param> ///<paramname="encoding"></param> ///<returns></returns> publicstaticobjectConvertFileToObject(stringpath,TypeobjectType,Encodingencoding) { objectconvertedObject=null; if(!string.IsNullOrEmpty(path)) { XmlSerializerser=newXmlSerializer(objectType); using(StreamReaderreader=newStreamReader(path,encoding)) { convertedObject=ser.Deserialize(reader); reader.Close(); } } returnconvertedObject; } } } 上面提到的WebService的那个问题,跟这个演示程序是一样的。 我们需要被序列化的内容中,存在低序位非打印ASCII字符时,.net会给我们正常序列化,会自动把低序位非打印ASCII字符转换成编码的字符(这个XML规范中要求这么做的)。 但是,反序列化时候,如果需要反序列化的内容如果存在编码的字符(映射到低序位非打印ASCII字符),则反序列化就会出错。 如果解决这个问题呢? 当然,最彻底的解决方法是修改反序列化的代码,让这些字符不会出错。但这个东西很多时候不归我们控制。这个方案不可行。 下一个方案就是剔除这些捣乱的字符。 我这里要给出的方案,是对这些字符序列化时作一次预处理,反序列化时,作一次反向处理。 这里为了演示的更有意义,我这里处理逻辑就是把低序位非打印ASCII字符转换成编码的字符,和把编码的字符转换成低序位非打印ASCII字符。 这样就可以使用我这里提供的函数,实现更多的处理逻辑。这两个函数的代码如下: ///<summary> ///把一个字符串中的低序位ASCII字符替换成字符 ///转换ASCII0-8->- ///转换ASCII11-12->- ///转换ASCII14-31->- ///</summary> ///<paramname="tmp"></param> ///<returns></returns> publicstaticstringReplaceLowOrderASCIICharacters(stringtmp) { StringBuilderinfo=newStringBuilder(); foreach(charccintmp) { intss=(int)cc; if(((ss>=0)&&(ss<=8))||((ss>=11)&&(ss<=12))||((ss>=14)&&(ss<=32))) info.AppendFormat("{0:X};",ss); elseinfo.Append(cc); } returninfo.ToString(); } ///<summary> ///把一个字符串中的下列字符替换成低序位ASCII字符 ///转换-->ASCII0-8 ///转换-->ASCII11-12 ///转换-->ASCII14-31 ///</summary> ///<paramname="input"></param> ///<returns></returns> publicstaticstringGetLowOrderASCIICharacters(stringinput) { if(string.IsNullOrEmpty(input))returnstring.Empty; intpos,startIndex=0,len=input.Length; if(len<=4)returninput; StringBuilderresult=newStringBuilder(); while((pos=input.IndexOf("",startIndex))>=0) { boolneedReplace=false; stringrOldV=string.Empty,rNewV=string.Empty; intle=(len-pos<6)?len-pos:6; intp=input.IndexOf(";",pos,le); if(p>=0) { rOldV=input.Substring(pos,p-pos+1); //计算对应的低位字符 shortss; if(short.TryParse(rOldV.Substring(3,p-pos-3),NumberStyles.AllowHexSpecifier,null,outss)) { if(((ss>=0)&&(ss<=8))||((ss>=11)&&(ss<=12))||((ss>=14)&&(ss<=32))) { needReplace=true; rNewV=Convert.ToChar(ss).ToString(); } } pos=p+1; } elsepos+=le; stringpart=input.Substring(startIndex,pos-startIndex); if(needReplace)result.Append(part.Replace(rOldV,rNewV)); elseresult.Append(part); startIndex=pos; } result.Append(input.Substring(startIndex)); returnresult.ToString(); } 这样,我们这个演示程序的Main函数修改为下面的代码,也不会有任何错误发生。 staticvoidMain(string[]args) { Console.WriteLine(GetLowOrderASCIICharacters("123456")); Console.WriteLine(GetLowOrderASCIICharacters("123456")); Console.WriteLine(GetLowOrderASCIICharacters("")); Console.WriteLine(GetLowOrderASCIICharacters("0123456789")); Console.WriteLine(GetLowOrderASCIICharacters("/f")); Console.WriteLine(GetLowOrderASCIICharacters("=-1")); Console.WriteLine(GetLowOrderASCIICharacters("")); Console.WriteLine(GetLowOrderASCIICharacters("")); stringfileName="d://1.txt"; MyClassc=newMyClass(); c.Value=string.Format("在神奇{0}天地裏誰叱咤風雨",Convert.ToChar(14)); c.Value=ReplaceLowOrderASCIICharacters(c.Value); SaveAsXML(c,fileName,Encoding.UTF8); objecto=ConvertFileToObject(fileName,typeof(MyClass),Encoding.UTF8); MyClassd=oasMyClass; if(d!=null) { d.Value=GetLowOrderASCIICharacters(d.Value); Console.WriteLine(d.Value); } elseConsole.WriteLine("null"); Console.ReadLine(); } 小结:低序位非打印ASCII字符在很多时候会给我们的系统带来问题,这部分字符必须作特殊处理。 |
相关文章推荐
- 获取xml时,出现“(十六进制值 0x1F)是无效的字符之类Xml异常的解决办法
- 安装SQL SERVER 2012失败,出现"."(十六进制0x00)是无效的字符,解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- xml序列化,异常:(十六进制值 0x1D)是无效的字符
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- XML 十六进制值 是无效的字符错误 解决方法之一 转
- android中获取文件的md5值时首位出现0被省略,而造成了只有31位字符的解决办法。
- C# 出现base-64 字符数组的无效长度的解决办法
- 使用记事本编写xml文件保存出现异常解决办法
- 操作XML 报错:根级别上的数据无效 和 给定编码中的字符无效 解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- C# 调用C++ DLL 返回类型为字符的接口 出现异常 解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- Spring Tool Suite首次使用pom.xml出现依赖异常解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法
- 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法