Wp7上的InvalidOperationException读取XML,xml声明和doctype之间没有CR

时间:2011-05-05 19:25:44

标签: xml silverlight windows-phone-7

我在WP7上加载XML,我发现如果我在XML声明和doctype之间没有换行符,即使我忽略了doctype,我也会得到 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类型的节点上。唯一的区别是缺少新的在第二种情况下排队。

有没有人见过这个,并找到了解决方法?这适用于桌面btw - 在WP7上失败。在我的实际情况中,我正在从流中读取XML,因此在正确的位置手动注入新行并不是那么容易。

达米安

2 个答案:

答案 0 :(得分:3)

现在我已经实现了一个注入NewLine的TextReader包装器。我将它包含在这里以防有人发现它有用,并且万一有人有更优雅的解决方案 - 如果有的话请评论!

它依赖于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(); }
}

答案 1 :(得分:0)

我不确定这是否优雅但它对我有用。我不确定发生了什么,如果你谷歌精确的错误信息,这是唯一的结果!

抛出的代码:

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函数有点松散,但我没有进一步挖掘。