c#中XML解析文件出错解决方法
来源:互联网 发布:c语言中文网知乎 编辑:程序博客网 时间:2024/06/14 14:47
在解析xml时,经常因为文件中含特殊字符而解析失败。原因有两个:一是内容中含有XML预定义好的实体,二是内容中含有低位非打印字符
1.内容中含有xml预定好的实体,如“<”和“&”,对xml来说是禁止使用的,针对这种字符,解决方式是使用CDATA部件以"<![CDATA[" 标记开始,以"]]>"标记结束,是CDATA内部内容被解析器忽略。具体说明参考《XML CDATA是什么?》。
2.内容中含有低位非打印字符,解析时会报错:""(十六进制值 0x1D)是无效的字符.加载或保存XML时引发的异常.System.ArgumentException: “”(十六进制值 0x1D)是无效的字符。
出错的原因是内容中含有低位非打印字符,处理方法是对其进行过滤,过滤方法为:
return System.Text.RegularExpressions.Regex.Replace(str,@"[\x00-\x08]|[\x0B-\x0C]|[\x0E-\x1F]";
以上两种情况,第一种较为普遍,第二种遇到情况比较少,在面对一些用户输入数据时生成xml,可以对xml结点内容执行上述过滤,以保证xml文件使用者可以正确解析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>
/// 反序列化
/// </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 字符 时, .net 会给我们正常序列化, 会自动把 低序位非打印 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 0 0
- c#中XML解析文件出错解决方法
- c#中XML解析文件出错解决方法
- C#解析XML文件
- C#解析XML文件
- C#解析XML文件
- C#解析XML文件
- C#解析XML文件
- c# 解析Xml文件
- C#解析XML文件
- C#解析XML文件
- C#解析XML文件
- C# 解析Xml文件
- Pull文件解析器解析xml文件出错解决
- C# xpath解析XML文件
- XML解析出错处理
- nsxmlparser解析xml出错
- nsxmlparser解析xml出错
- JAVA中解析XML文件
- 游戏中不能使用点卡
- XmlDocument.LoadXml上的坑
- WIN7 64位找不到Driver do Microsoft Access(*.mdb)ODBC驱动程序
- Android 退出整个应用程序
- IOS开发基础—UITableView的基本使用。
- c#中XML解析文件出错解决方法
- mysql中列转行
- layout_gravity和gravity的区别(很简单)
- SSH面试题
- spring jpa整合junit单元测试 ,设置事务自动回滚
- CocoaPods的安装与使用
- Android:Layout_weight的深刻理解
- 【设计模式】策略设计模式
- 【POJ】3070Fibonacci(矩阵快速幂)