XML⽂件出错解决⽅法!(转)
“”(⼗六进制值 0x1D)是⽆效的字符
加载或保存XML时引发的异常.System.ArgumentException: “”(⼗六进制值 0x1D)是⽆效的字符。
产⽣原因是xml⽂件中包含低位⾮打印字符造成的
处理⽅法:在产⽣xml⽂件的时候,过滤低位⾮打印字符
把⼀个字符串中的低序位 ASCII 字符替换成 &#x 字符
转换 ASCII 0 - 8 -> � - 
转换 ASCII 11 - 12 -> -
转换 ASCII 14 - 31 ->  - 
return System.Text.RegularExpressions.Regex.Replace(HttpUtility.HtmlEncode(str),@"[\x00-\x08]|[\x0B-\x0C]|[\x0E-\x1F]", "");
======================================================================================================================== ==============================
复杂处理
获取xml时,出现“(⼗六进制值 0x1F)是⽆效的字符之类Xml异常的解决办法2008-12-19 10:44最近做新闻采集器,需要获取很多站点的xml,加载个别站点经常出现“(⼗六进制值 0x1F)是⽆效的字符”问题,百思不的其解。对于问题站点xml的处理,开始的思路是既然直接⽤ XmlDocument对象的Load()⽅法不⾏,就⽤LoadXML() ,⽤HttpWebRequest 获取url读到流⾥再转为xml,中间可以加⼀些⾮有效字符的过滤处理,但仍然⽆效,仅仅解决了请求超时的问题...
问题搁置了1周后,终于在今天解决了。
其实很简单,只加⼀条语句就搞定了
XmlDocument doc = new XmlDocument();
doc.Normalize();
// 摘要:
//    将此 XmlNode 下⼦树完全深度中的所有 XmlText 节点都转换成“正常”形式,在这种形式中只有标记(即标记、注释、处理指令、CDATA //    节和实体引⽤)分隔 XmlText 节点,也就是说,没有相邻的 XmlText 节点。
以下是转⼀位仁兄的贴:
最近碰到⼀个问题,我的⼀个把数据库中记录的信息暴露出来的Web Service调⽤时候出问题了。报下⾯的错误信息:
System.InvalidOperationException was unhandled
Message="XML ⽂档(1, 823)中有错误。"
Source="System.Xml"
Message="“”(⼗六进制值 0x0E)是⽆效的字符。⾏ 1,位置 823。"
Source="System.Xml"
当这个错误发⽣时,Web Service 服务器端不会有任何错误,⽽调⽤这个 Web Service 的客户端则会报上述错误。
是何原因导致的这个问题呢?
答案很简单,是WEB Service 暴露的XML⽂档中存在低序位⾮打印 ASCII 字符所致。
我们查看 Web Service 返回的XML ⽂档⽂档中,会有下⾯的XML⽂档节:其中的就是低序位 ASCII 字符。对应的字符如后:
<Value> 在神奇天地裏誰叱咤⾵⾬</Value>
会导致这些问题的低序位⾮打印 ASCII 字符包含以下字符:
#x0 - #x8 (ASCII 0 - 8)
#xB - #xC (ASCII 11 - 12)
#xE - #x1F (ASCII 14 - 31)
下⾯就是⼀个简单演⽰这个问题的控制台程序,
为了简单起见,这⾥没有建⽴ WebService,⽽是把⼀个类XML序列化存储到⽂件,然后再把这个⽂件反序列化读取出来:
其中的这个类的Value值中,放了⼀个低序位⾮打印 ASCII 字符。
执⾏这个控制台程序,就会报异常。“XML ⽂档(3, 12)中有错误。”
using System;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Globalization;
namespace TextSerialize
{
[Serializable]
public class MyClass
{
public string Value { get; set; }
}
class Program
{
static void Main(string[] args)
{
string fileName = "d:\\1.txt";
MyClass c = new MyClass();
c.Value = string.Format("在神奇{0}天地裏誰叱咤⾵⾬", Convert.ToChar(14)); SaveAsXML(c, fileName, Encoding.UTF8);
object o = ConvertFileToObject(fileName, typeof(MyClass), Encoding.UTF8);
MyClass d = o as MyClass;
if (d != null) Console.WriteLine(d.Value);
else Console.WriteLine("null");
Console.ReadLine();
}
/// <summary>
/// 序列化
/// </summary>
/// <param name="objectToConvert"></param>
/// <param name="path"></param>
/// <param name="encoding"></param>
public static void SaveAsXML(object objectToConvert, string path, Encoding encoding)
{
if (objectToConvert != null)
{
Type t = objectToConvert.GetType();
XmlSerializer ser = new XmlSerializer(t);
using (StreamWriter writer = new StreamWriter(path, false, encoding))
{
ser.Serialize(writer, objectToConvert);
writer.Close();
}
}
}
/// <summary>
/// 反序列化getsavefilename
/// </summary>
/// <param name="path"></param>
/// <param name="objectType"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static object ConvertFileToObject(string path, Type objectType, Encoding encoding) {
object convertedObject = null;
if (!string.IsNullOrEmpty(path))
{
XmlSerializer ser = new XmlSerializer(objectType);
using (StreamReader reader = new StreamReader(path, encoding))
{
convertedObject = ser.Deserialize(reader);
reader.Close();
}
}
return convertedObject;
}
}
上⾯提到的Web Service 的那个问题,跟这个演⽰程序是⼀样的。
我们需要被序列化的内容中,存在低序位⾮打印 ASCII 字符时, 会给我们正常序列化,会⾃动把低序位⾮打印 ASCII 字符转换成 &#x 编码的字符(这个XML规范中要求这么做的)。
但是,反序列化时候,如果需要反序列化的内容如果存在 &#x 编码的字符(映射到低序位⾮打印 ASCII 字符),则反序列化就会出错。
如果解决这个问题呢?
当然,最彻底的解决⽅法是修改反序列化的代码,让这些字符不会出错。但这个东西很多时候不归我们控制。这个⽅案不可⾏。
下⼀个⽅案就是剔除这些捣乱的字符。
我这⾥要给出的⽅案,是对这些字符序列化时作⼀次预处理,反序列化时,作⼀次反向处理。
这⾥为了演⽰的更有意义,我这⾥处理逻辑就是把低序位⾮打印 ASCII 字符转换成 &#x 编码的字符,和把&#x 编码的字符转换成低序位⾮打印 ASCII 字符。
这样就可以使⽤我这⾥提供的函数,实现更多的处理逻辑。这两个函数的代码如下:
/// <summary>
/// 把⼀个字符串中的低序位 ASCII 字符替换成 &#x 字符
/// 转换 ASCII 0 - 8 -> � - 
/// 转换 ASCII 11 - 12 -> -
/// 转换 ASCII 14 - 31 ->  - 
/// </summary>
/// <param name="tmp"></param>
/// <returns></returns>
public static string ReplaceLowOrderASCIICharacters(string tmp)
{
StringBuilder info = new StringBuilder();
foreach (char cc in tmp)
{
int ss = (int)cc;
if (((ss >= 0) && (ss <= 8)) || ((ss >= 11) && (ss <= 12)) || ((ss >= 14) && (ss <= 32)))
info.AppendFormat("&#x{0:X};", ss);
else info.Append(cc);
}
return info.ToString();
}
/// <summary>
/
// 把⼀个字符串中的下列字符替换成低序位 ASCII 字符
/// 转换 � -  -> ASCII 0 - 8
/// 转换 - -> ASCII 11 - 12
/// 转换  -  -> ASCII 14 - 31
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string GetLowOrderASCIICharacters(string input)
{
if (string.IsNullOrEmpty(input)) return string.Empty;
int pos, startIndex = 0, len = input.Length;
if (len <= 4) return input;
StringBuilder result = new StringBuilder();
while ((pos = input.IndexOf("&#x", startIndex)) >= 0)
{
bool needReplace = false;
string rOldV = string.Empty, rNewV = string.Empty;
int le = (len - pos < 6) ? len - pos : 6;
int p = input.IndexOf(";", pos, le);
if (p >= 0)
rOldV = input.Substring(pos, p - pos + 1);
// 计算对应的低位字符
short ss;
if (short.TryParse(rOldV.Substring(3, p - pos - 3), NumberStyles.AllowHexSpecifier, null, out ss)) {
if (((ss >= 0) && (ss <= 8)) || ((ss >= 11) && (ss <= 12)) || ((ss >= 14) && (ss <= 32)))
{
needReplace = true;
rNewV = Convert.ToChar(ss).ToString();
}
}
pos = p + 1;
}
else pos += le;
string part = input.Substring(startIndex, pos - startIndex);
if (needReplace) result.Append(part.Replace(rOldV, rNewV));
else result.Append(part);
startIndex = pos;
}
result.Append(input.Substring(startIndex));
return result.ToString();
}
这样,我们这个演⽰程序的 Main 函数修改为下⾯的代码,也不会有任何错误发⽣。
static void Main(string[] args)
{
Console.WriteLine(GetLowOrderASCIICharacters("123456

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论