InvalidOperationException при wp7, читающем XML без CR между объявлением xml и типом документа - PullRequest
7 голосов
/ 05 мая 2011

Я загружаю XML в WP7 и обнаруживаю, что если у меня нет новой строки между объявлением XML и типом документа, даже если я игнорирую тип документа, я получаю InvalidOperationException . На рабочем столе такой ошибки нет.

Мой код:

private static void Example()
{
    const string works =
        @"<?xml version=""1.0""?>
<!DOCTYPE example SYSTEM ""http://example.com/example.dtd""><hello></hello>";

    const string fails =
        @"<?xml version=""1.0""?><!DOCTYPE example SYSTEM ""http://example.com/example.dtd""><hello></hello>";

    var textReader = new StringReader(works);  
    var xmlReaderSettings = new XmlReaderSettings {DtdProcessing = DtdProcessing.Ignore,};
    var xmlReader = XmlReader.Create(textReader, xmlReaderSettings);
    XDocument.Load(xmlReader);  // No problem here

    textReader = new StringReader(fails);  

    xmlReader = XmlReader.Create(textReader, xmlReaderSettings);
    XDocument.Load(xmlReader);  // Fails here
}

Второй XDocument.Load завершается с ошибкой InvalidOperationException и сообщением . XmlReader не должен находиться на узле типа XmlDeclaration. Единственным отличием является отсутствие новой строки в второй случай.

Кто-нибудь видел это раньше и нашел обходной путь? Это работает на рабочем столе, кстати, просто не работает на WP7. В моем реальном случае я читаю XML из потока, поэтому будет нелегко вручную вставить новую строку в нужном месте.

Damian

Ответы [ 2 ]

3 голосов
/ 06 мая 2011

На данный момент я реализовал обертку TextReader, которая внедряет NewLine.Я включил это здесь, если кто-то найдет это полезным, а также если у кого-то есть более элегантное решение - если так, пожалуйста, прокомментируйте!

Он опирается только на XmlReader, вызывающий метод Read (...)для чтения данных - в противном случае выдается NotImplementedException.

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

textReader = new NewlineAfterXmlDeclReader(new StringReader(fails));  

Это реализация

class NewlineAfterXmlDeclReader : TextReader
{
    private const int InitialChunkSize = 80;
    private const string SearchText = "?><!" + "DOCTYPE";  //concatenation injected for readability in SO purposes only
    private static readonly string ReplaceText = "?>" + Environment.NewLine + "<!" + "DOCTYPE";

    private readonly TextReader _wrappedReader;
    private TextReader _firstChunkReader;

    public NewlineAfterXmlDeclReader(TextReader wrappedReader)
    {
        _wrappedReader = wrappedReader;
        var initialChunk = new char[InitialChunkSize];
        var count = _wrappedReader.Read(initialChunk, 0, InitialChunkSize);
        var initialChunkString = new String(initialChunk, 0, count);

        _firstChunkReader = new StringReader(initialChunkString.Replace(SearchText, ReplaceText));
    }

    public override int Read(char[] buffer, int index, int count)
    {
        var firstChunkReadCount = 0;
        if (_firstChunkReader != null)
        {
            firstChunkReadCount = _firstChunkReader.ReadBlock(buffer, index, count);
            if (firstChunkReadCount == count) return firstChunkReadCount;
            _firstChunkReader = null;
            index += firstChunkReadCount;
            count -= firstChunkReadCount;
        }

        return firstChunkReadCount + _wrappedReader.Read(buffer, index, count);
    }

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

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

    public override int Peek() { throw new NotImplementedException(); }
    public override int Read() { throw new NotImplementedException(); }
    public override string ReadToEnd() { throw new NotImplementedException(); }
    public override int ReadBlock(char[] buffer, int index, int count) { throw new NotImplementedException(); }
    public override string ReadLine() { throw new NotImplementedException(); }
}
0 голосов
/ 25 августа 2011

Я не уверен, элегантно ли это, но у меня это сработало.Я не уверен, что происходит, хотя, если вы гуглите точное сообщение об ошибке, это единственный результат!

Код, который выдает:

WebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = (int)_Timeout.TotalMilliseconds;

using (var resp = (HttpWebResponse)request.GetResponse())
{
  using (XmlReader reader = XmlTextReader.Create(resp.GetResponseStream()))
  {
    reader.Read();
    return (XElement)XElement.ReadFrom(reader);
  }
}

Код, который счастлив:

WebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = (int)_Timeout.TotalMilliseconds;

using (var resp = (HttpWebResponse)request.GetResponse())
{
  using (var responseStream = resp.GetResponseStream())
  {
    using (var reader = new StreamReader(responseStream, Encoding.ASCII))
    {
      string raw = reader.ReadToEnd();
      return (XElement)XElement.Parse(raw);
    }
  }
}

По какой-то причине чтение ответа в строку и передача его в функцию Parse () делает что-то отличное от использования функции ReadFrom () и потока.Потенциально функция Parse немного более свободна, но я больше не копался.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...