XML — System.Xml.XmlException — шестнадцатеричное значение 0x06

Я получаю эту ошибку. Позже я искал и выяснил причину недопустимых символов в моем XML и ее решение. Но у меня нет доступа для редактирования любого из этих файлов. Моя работа состоит в том, чтобы читать и извлекать значение тега, значение атрибута и тому подобное. ТАК Я не могу заменить двоичные символы экранами, такими как «\ x01» на & # 01. Также я попытался включить CheckCharacters = false в настройках XMLreader. Этого не требуется. Все равно выдает ту же ошибку.

Неужели нельзя исправить в XMLreader? Я читал о XMLtextReader. Он может пропустить исключение. Но я уже закодировал все свои функции с помощью XMLreader. Было бы хорошо, если бы я мог найти решение для этого. В противном случае мне пришлось бы изменить весь мой код.

Мой код:

  private void button1_Click(object sender, EventArgs e)
        {
            int i = 0;
            var filenames = System.IO.Directory
                        .EnumerateFiles(textBox1.Text, "*.xml", System.IO.SearchOption.AllDirectories)
                        .Select(System.IO.Path.GetFullPath);



            foreach (var f in filenames)
            {
                var resolver = new XmlUrlOverrideResolver();
                resolver.DtdFileMap[@"X1.DTD"] = @"\\location\X1.DTD";
                resolver.DtdFileMap[@"R2.DTD"] = @"\\location\X2.DTD";
                resolver.DtdFileMap[@"R5.DTD"] = @"\\location\R5.DTD";
                XmlReaderSettings settings = new XmlReaderSettings();

                settings.DtdProcessing = DtdProcessing.Parse;
                settings.XmlResolver = resolver;
                XmlReader doc = XmlReader.Create(f, settings);
                while (doc.Read())
                {
                    if ((doc.NodeType == XmlNodeType.Element) && (doc.Name == "ap"))
                {
                    if (doc.HasAttributes)
                    {

                        String fin = doc.GetAttribute("ap");
                        if (fin == "no")
                        {


                            String[] array = new String[10000];
                            array[i] = (f);

                            File.AppendAllText(@"\\location\NAPP.txt", array[i] + Environment.NewLine);
                            i++;
                        }
                        else
                        {
                            String[] abs = new String[10000];
                            abs[i] = (f);
                            File.AppendAllText(@"\\location\APP.txt", abs[i] + Environment.NewLine);
                            i++;
                        }
                    }

                }
            }
        }

        MessageBox.Show("Done");
    }

person Shahul Hameed    schedule 23.02.2015    source источник


Ответы (2)


Это очень простой пример символьного «фильтра», который заменяет символ 0x06 пробелом:

public class MyStreamReader : StreamReader {
    public MyStreamReader(string path)
        : base(path) {
    }

    public override int Read(char[] buffer, int index, int count) {            
        int res = base.Read(buffer, index, count);

        for (int i = 0; i < res; i++) {
            if (buffer[i] == 0x06) {
                buffer[i] = ' ';
            }
        }

        return res;
    }
}

Вы используете его следующим образом:

using (var sr = new MyStreamReader(f)) {
    var doc = XmlReader.Create(sr, settings);

Обратите внимание, что это очень просто, потому что заменяет символ (0x06) другим символом той же «длины» (пробелом). Если бы вы хотели заменить символ «последовательностью» символов (чтобы избежать этого), это стало бы более сложным (не невозможно, 30 минут работы сложно)

(Я проверил, и кажется, что XmlTextReader использует только этот метод, а не метод Read())

Как всегда, когда программист говорит вам 30 минут, это означает 0 минут или 2 часа :-)

Это "более сложный" ReplacingStreamReader:

/// <summary>
/// Only the Read methods are supported!
/// </summary>
public class ReplacingStreamReader : StreamReader
{
    public ReplacingStreamReader(string path)
        : base(path)
    {
    }

    public Func<char, string> ReplaceWith { get; set; }

    protected char[] RemainingChars { get; set; }
    protected int RemainingCharsIndex { get; set; }


    public override int Read()
    {
        int ch;

        if (RemainingChars != null)
        {
            ch = RemainingChars[RemainingCharsIndex];
            RemainingCharsIndex++;

            if (RemainingCharsIndex == RemainingChars.Length)
            {
                RemainingCharsIndex = 0;
                RemainingChars = null;
            }
        }
        else
        {
            ch = base.Read();

            if (ch != -1)
            {
                string replace = ReplaceWith((char)ch);

                if (replace == null)
                {
                    // Do nothing
                }
                else if (replace.Length == 1)
                {
                    ch = replace[0];
                }
                else
                {
                    ch = replace[0];

                    RemainingChars = replace.ToCharArray(1, replace.Length - 1);
                    RemainingCharsIndex = 0;
                }
            }
        }

        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        int res = 0;

        // We leave error handling to the StreamReader :-)
        // We handle only "working" parameters
        if (RemainingChars != null && buffer != null && index >= 0 && count > 0 && index + count <= buffer.Length)
        {
            int remainingCharsCount = RemainingChars.Length - RemainingCharsIndex;
            res = Math.Min(remainingCharsCount, count);

            Array.Copy(RemainingChars, RemainingCharsIndex, buffer, index, res);

            RemainingCharsIndex += res;

            if (RemainingCharsIndex == RemainingChars.Length)
            {
                RemainingCharsIndex = 0;
                RemainingChars = null;
            }

            if (res == count)
            {
                return res;
            }

            index += res;
            count -= res;
        }

        while (true)
        {
            List<char> sb = null;

            int res2 = base.Read(buffer, index, count);

            if (res2 == 0 || ReplaceWith == null)
            {
                return res;
            }

            int j = 0;

            for (int i = 0; i < res2; i++)
            {
                char ch = buffer[index + i];
                string replace = ReplaceWith(ch);

                if (sb != null)
                {
                    if (replace == null)
                    {
                        sb.Add(ch);
                    }
                    else
                    {
                        sb.AddRange(replace);
                    }
                }
                else if (replace == null)
                {
                    buffer[j] = ch;
                    j++;
                }
                else if (replace.Length == 1)
                {
                    buffer[j] = replace[0];
                    j++;
                }
                else if (replace.Length == 0)
                {
                    // We do not advance
                }
                else
                {
                    sb = new List<char>();
                    sb.AddRange(replace);
                }
            }

            res2 = j;

            if (sb != null)
            {
                int res3 = Math.Min(sb.Count, count - res2);
                sb.CopyTo(0, buffer, index + res2, res3);

                if (res3 < sb.Count)
                {
                    RemainingChars = new char[sb.Count - res3];
                    RemainingCharsIndex = 0;
                    sb.CopyTo(res3, RemainingChars, 0, RemainingChars.Length);
                }

                res += res3;
            }
            else
            {
                res2 = j;

                // Can't happen if sb != null (at least a character must
                // have been added)
                if (res2 == 0)
                {
                    continue;
                }
            }

            res += res2;
            return res;
        }
    }
}

Используйте это как:

using (var sr = new ReplacingStreamReader(f))
{
    sr.ReplaceWith = x =>
    {
        return x == 0x6 ? " " : null;
        // return x == '.' ? "&#160;" : null; // Replace all . with &nbsp;
    };

    var doc = XmlReader.Create(sr, settings);

Имейте в виду, что ReplacingStreamReader не «знает», какую часть xml он модифицирует, поэтому редко допускается «слепая» замена :-) Помимо этого ограничения, вы можете заменить любой символ любой строкой (null в ReplaceWith означает «сохранить текущий символ», что эквивалентно x.ToString() в приведенном примере. Возврат string.Empty действителен, означает удаление текущего символа).

Класс довольно интересный: он хранит char[] RemainingChars с символами, которые были прочитаны (и отфильтрованы ReplaceWith), но не были возвращены методом Read(), потому что переданный буфер был слишком мал (метод ReplaceWith мог "увеличить" прочитанная строка, что делает ее слишком большой для buffer!). Обратите внимание, что sb — это List<char>, а не StringBuilder. Вероятно, использование одного или другого было бы почти эквивалентно с точки зрения кода.

person xanatos    schedule 23.02.2015
comment
(а) не должно ли это быть 0x01 и (б) я думаю, что ОП хочет заменить символы... - person Willem Van Onsem; 23.02.2015
comment
@CommuSoft В заголовке написано 0x06 :-) Но это можно быстро изменить, и это быстрое решение. Как я уже писал, сделать полную замену становится сложнее. - person xanatos; 23.02.2015
comment
Большое спасибо :) Это сработало чудесно. Извините за позднее признание. Я болел последние 2 недели и сегодня вернулся к работе. Спасибо за вашу помощь. - person Shahul Hameed; 12.03.2015

Вы можете сначала прочитать содержимое в string заменить (экранировать) содержимое, а затем загрузить его в XmlReader:

foreach (var f in filenames) {
    string text;
    using (StreamReader s = new StreamReader(f,Encoding.UTF8)) {
        text = s.ReadToEnd();
    }
    text = text.Replace("\x01",@"&#01"); //replace the content

    //load some settings
    var resolver = new XmlUrlOverrideResolver();
    resolver.DtdFileMap[@"X1.DTD"] = @"\\location\X1.DTD";
    resolver.DtdFileMap[@"R2.DTD"] = @"\\location\X2.DTD";
    resolver.DtdFileMap[@"R5.DTD"] = @"\\location\R5.DTD";
    XmlReaderSettings settings = new XmlReaderSettings();

    settings.DtdProcessing = DtdProcessing.Parse;
    settings.XmlResolver = resolver;
    XmlReader doc = XmlReader.Create(text, settings);

    //perform processing task
    //...
}
person Willem Van Onsem    schedule 23.02.2015