【问题标题】:Invalid Hexadecimal Characters in XMLXML 中的无效十六进制字符
【发布时间】:2016-01-07 04:52:01
【问题描述】:

我有一个包含无效十六进制字符的 XML。我已阅读 thisthisthis 以及任何其他链接,但未能成功。

我正在使用 XmlReader - XmlDocumentXDocumentXmlTextReader 不是我的选择,因为有超过 500GB 大小和 5 亿容量的 XML 文件。 XMLReader 是我的最佳选择,因为它采用“前向”方法,并且不会将所有 XML 详细信息加载到内存中。此外,正因为如此,我不能重新创建或加载 XML 文件来替换无效字符。

这是我正在处理的代码:

case XmlNodeType.Element:
if (xmlReader.Name.Equals("ROW"))
{
    DataRow dataRow = xmlDataTable.NewRow();
    XmlReader row = XmlReader.Create(xmlReader.ReadSubtree(), new XmlReaderSettings { CheckCharacters = false
                                                                            , ValidationType = ValidationType.None });

    // iterate on elements inside ROW
    // these are the column items
    if (row != null)
    {
        while (row.Read())
        {

            if (row.IsStartElement())
            {

                if (!row.Name.Equals("ROW"))
                {

                    string columnName = row.Name;
                    //row = XmlReader.Create(CleanInvalidXmlChars(row.ReadInnerXml()));

                    row.Read();
                    string value = CleanInvalidXmlChars(row.Value.ToString());

                    // all other logics ...

row.Read(); 语句引发异常。这是我正在阅读的示例 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<MFAINSBRP>
<ROW>
    <INSTITUTION_CODE>828  </INSTITUTION_CODE>
    <BRANCH_CODE>GJ102</BRANCH_CODE>
    <BRANCH_NAME>                                   </BRANCH_NAME>
    <BRANCH_NAME_FRENCH>                                   </BRANCH_NAME_FRENCH>
    <LANGUAGE_CODE>E</LANGUAGE_CODE>
    <ADDR_NO>815412</ADDR_NO>
    <FAX_AREA>0</FAX_AREA>
    <FAX_PHONE>0</FAX_PHONE>
    <AREA_CODE>0</AREA_CODE>
    <PHONE_NO>0</PHONE_NO>
    <STATUS>A</STATUS>
    <PHONE_EXT>0</PHONE_EXT>
</ROW>
<!--ALL OTHER RECORDS-->
</MFAINSBRP>

现在,我坚持做这项工作。

编辑:

示例 XML 文件是使我的代码中断的记录。我从 Notepad++ 复制粘贴在这里,但它没有显示无效字符。这是它在 Notepad++ 中的样子:

我如何创建xmlReader 对象就是这个简单的语句:

using (xmlReader = XmlReader.Create(filePath, new XmlReaderSettings { CheckCharacters = false }))

【问题讨论】:

  • 文件在哪里失败了?我希望异常会向您显示行/列。
  • 此示例 XML 是否包含会破坏您的代码的问题输入示例?如果是这样,你能以某种方式突出它吗?如果没有,您能否创建一个确实显示问题的示例?
  • stackoverflow.com/questions/5742543/… 可能是相关的。该文件是错误的,因此您需要先对其进行预处理并删除有问题的字符。您也许可以使用中间流来做到这一点。
  • 这应该和读入数据库有些关系。如果是这样,那么使用后端数据库的 XML 读取功能不是更可行。 "Invalid hexadecimal characters" - 一个十六进制字符怎么会是无效的。
  • 您最初提供的 XML 文件很好 - 因为您粘贴了空格而不是其他任何内容。现在您已经在 Notepad++ 中展示了它,我们可以看到它为什么会损坏……是的,它只是无效的 XML。您从哪里获得 XML?你能解决这个问题吗?在可能的情况下,您最好确保永远不会有无效数据,而不是稍后尝试清理它。

标签: c# xml


【解决方案1】:

我不清楚为什么 CheckCharacters = false 没有为您解决问题,正如我所提到的,远远更好的解决方法是以干净的方式开始获取数据与。

但是,您可以通过用 XmlReader 使用的 TextReader 中的替换替换每个无效字符来解决此问题。这是一个简短但完整的示例:

using System;
using System.IO;
using System.Xml;

class Test
{
    static void Main()
    {
        var text = "<foo>\0</foo>";
        var reader = XmlReader.Create(
             new XmlReplacingReader(new StringReader(text), ' '));
        while (reader.Read())
        {
            Console.WriteLine(reader.NodeType);
        }
    }
}

public sealed class XmlReplacingReader : TextReader
{
    private readonly TextReader original;
    private readonly char replacementChar;

    public XmlReplacingReader(TextReader original, char replacementChar)
    {
        this.original = original;
        this.replacementChar = replacementChar;
    }

    override public int Peek()
    {
        int ret = original.Peek();
        return MaybeReplace(ret);
    }

    override public int Read()
    {
        int ret = original.Read();
        return MaybeReplace(ret);        
    }

    override public int Read(char[] buffer, int index, int count)
    {
        int ret = original.Read(buffer, index, count);
        for (int i = 0; i < ret; i++)
        {
            buffer[i + index] = MaybeReplace(buffer[i + index]);
        }
        return ret;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            original.Dispose();
        }
    }

    public override void Close()
    {
        original.Close();
    }

    private int MaybeReplace(int x)
    {
        return x < 0 ? x : MaybeReplace((char) x);
    }

    private char MaybeReplace(char c)
    {
        return (c >= ' ' || c == '\r' || c == '\n' || c == '\t') ? c : replacementChar;
    }
}

当然,这依赖于您能够为文件创建TextReader - 如果您知道编码,您可以使用File.OpenText 执行此操作。如果您需要处理其他编码,您可能需要更巧妙的解决方案,但这应该可以帮助您入门。

请注意,这种方法替换无效字符。如果你想删除它们,它会变得更难并且可能效率更低,因为批量 Read 方法需要确定它是否需要删除字符,执行删除,然后返回不同的值。代码会更棘手 - 我希望你不需要它。

【讨论】:

  • 是的,我也想知道为什么CheckCharacters 不适用于这种情况。我已经完成了许多其他可以正常运行的场景,但是现在,我什至不知道我做错了什么。一段时间以来一直在查看您的代码 sn-p,将尝试实现这一点并更新任何内容。
猜你喜欢
  • 2011-12-31
  • 2012-11-24
  • 1970-01-01
  • 2012-09-10
  • 1970-01-01
  • 2012-06-17
  • 2016-11-14
  • 2016-03-30
  • 1970-01-01
相关资源
最近更新 更多