【问题标题】:Different behaviour between "new XmlTextReader" and "XmlReader.Create"“new XmlTextReader”和“XmlReader.Create”之间的不同行为
【发布时间】:2016-03-19 08:29:08
【问题描述】:

给出以下源代码:

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

 namespace TheXMLGames
 {
   class Program
   {
     static void Main(string[] args)
     {
       XmlReaderSettings settings = new XmlReaderSettings {
         Async = false,
         ConformanceLevel = ConformanceLevel.Fragment,
         DtdProcessing = DtdProcessing.Ignore,
         ValidationFlags = XmlSchemaValidationFlags.None,
         ValidationType = ValidationType.None,
         XmlResolver = null,
       };

       string head = File.ReadAllText("sample.xml");
       Stream stringStream = GenerateStreamFromString(head);

       // Variant 1
       //XmlReader reader = XmlReader.Create(stringStream);

       // Variant 2
       //XmlReader reader = XmlReader.Create(stringStream, settings);

       // Variant 3
       XmlTextReader reader = new XmlTextReader(stringStream);

       while (reader.Read())
         if (reader.NodeType != XmlNodeType.Whitespace)
           Console.WriteLine(reader.Name + ": " + reader.Value);

       // No Variant gets here without an exception,
       // but that's not the point!

       Console.ReadKey();
     }

     public static Stream GenerateStreamFromString(string s)
     {
       MemoryStream stream = new MemoryStream();
       StreamWriter writer = new StreamWriter(stream);
       writer.Write(s);
       writer.Flush();
       stream.Position = 0;
       return stream;
     }
   }
 }

示例.xml

 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TestingFacility >
 <TestingFacility id="MACHINE_2015-11-11T11_11_11" version="2015-11-11">

 <Program>
   <Title>title</Title>
   <Steps>16</Steps>
 </Program>
 <Calibration>
   <Current offset="0" gain="111.11" />
   <Voltage offset="0" gain="111.11" />
 </Calibration>
 <Info type="Facilityname" value="MACHINE" />
 <Info type="Hardwareversion" value="HW11" />
 <Info type="Account" value="DJohn" />
 <Info type="Teststart" value="2015-11-11T11:11:11" />
 <Info type="Description" value="desc" />
 <Info type="Profiler" value="prof" />
 <Info type="Target" value="trgt" />

行为如下:

变体 1
XmlReader.Create(流)
System.Xml.dll 中出现“System.Xml.XmlException”类型的未处理异常 附加信息:出于安全原因,此 XML 文档中禁止使用 DTD。要启用 DTD 处理,请将 XmlReaderSettings 上的 DtdProcessing 属性设置为 Parse 并将设置传递给 XmlReader.Create 方法。

变体 2
XmlReader.Create(流,设置)
System.Xml.dll 中出现“System.Xml.XmlException”类型的未处理异常 附加信息:意外的 DTD 声明。第 2 行,位置 3。

变体 3
新 XmlTextReader(stringStream)
System.Xml.dll 中出现“System.Xml.XmlException”类型的未处理异常 附加信息:文件意外结束。以下元素未关闭:TestingFacility。第 19 行,位置 36。

变体 1 和 2 在第一行之后抛出。
变体 3 按预期输出整个文件,当它到达末尾时,它会抱怨(正确!)。

该软件的工作原理与我显然使用 Variant 3 一样,但(现在)推荐的方法是通过 XmlReader.Create 使用 Factory

如果我摆弄设置,它会开始变得更加奇怪。

如何获取最新代码并使用 XmlReader.Create?

完整的项目可以在这里找到: https://drive.google.com/file/d/0B55cC50M31_8T0lub25oS2QxQ00/view

【问题讨论】:

  • 这是一个相关问题(不是重复的!)stackoverflow.com/questions/1551912/…
  • XmlReader 表示提供对 XML 数据的快速、非缓存、只进访问的读取器。 XmlTextReader 提供完整的功能。 XmlReader 较新,已修复 XmlTextReader 中的错误。
  • @jdweng:XmlReader 只是 XmlTextReader 的基类,允许其他派生类,例如在 DOM 上提供相同的 API。正如您所暗示的那样,它不像是另一个的固定版本。
  • 我猜新类比旧版本更健壮。不是真正的错误。
  • 您可能想查看 this post,其中包含一些关于 XmlTextReader 与使用 .Create 方法创建的 XmlReader 的讨论。出于安全原因(DTD 扩展 DOS 攻击),默认情况下,在使用 .Create() 创建的 XmlReader 中禁用处理 DTD。

标签: c# xml xml-parsing linq-to-xml


【解决方案1】:

我通常不建议使用非 XML 方法来解析 XML 文件。但有时当 XML 无效时,其他方法是更好的选择。由于您有一个巨大的 XML 文件,并且您只想获取一行数据,因此下面的代码可能是最佳选择。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<!DOCTYPE SomeDocTypeIdidntPutThere>\n" +
                "<TestingFacility id=\"MACHINE2_1970-01-01T11_22_33\" version=\"1970-01-01\">\n" +
                "<Program>\n" +
                  "<Title>Fancy Title</Title>\n" +
                  "<Steps>136</Steps>\n" +
                "</Program>\n" +
                "<Info type=\"Start\" value=\"2070-01-01T11:22:33\" />\n" +
                "<Info type=\"LotMoreOfThem\" value=\"42\" />\n";

            MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
            StreamReader reader = new StreamReader(stream);
            string inputLine = "";
            string timeStr = "";
            while ((inputLine = reader.ReadLine()) != null)
            {
                inputLine = inputLine.Trim();
                if(inputLine.StartsWith("<Info type=\"Start\""))
                {
                    string pattern = "value=\"(?'time'[^\"]+)";
                    timeStr = Regex.Match(inputLine, pattern).Groups["time"].Value;
                    break;
                }
            }
            DateTime time;
            if (timeStr.Length > 0)
            {
                time = DateTime.Parse(timeStr);
            }
        }
    }
}

​

【讨论】:

  • 感谢您的提示,但正如我之前提到的,正则表达式始终是一种“解决方案”。奇怪的事情(到目前为止没人能解释 :-))是,它与 XmlTextReader 一起工作。我理解不完整 XML 的困难,正如我所提到的,SAX 可能是更好的选择。我想了解它为什么会这样。
  • 正如我所提到的,如果您将 MemoryStream 方法与 XmlTextReader 一起使用,它可以正常工作。而且我认为它也应该适用于 XmlReader.Create 的正确设置,但我无法弄清楚它们,在我提交问题之前,我只是想看看我是否忘记了一些重要的事情。
  • 哦,由于属性的未知顺序,正则表达式方法更加健壮。
【解决方案2】:

您的 xml 无效。您缺少结束标记,并且 DOCTYPE 必须与根标记匹配

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TestingFacility>
<TestingFacility id="MACHINE2_1970-01-01T11_22_33" version="1970-01-01">

  <Program>
    <Title>Fancy Title</Title>
    <Steps>136</Steps>
  </Program>
  <Info type="Start" value="2070-01-01T11:22:33" />
  <Info type="LotMoreOfThem" value="42" />
</TestingFacility>​

【讨论】:

  • 请阅读这个问题(如:到最后)但无论如何,谢谢,我会让 DTD 匹配结束标签,尽管如此,给定的设置应该完全忽略它。另外:例外不是关于不正确的命名!
猜你喜欢
  • 2010-12-05
  • 2017-02-22
  • 2014-11-01
  • 1970-01-01
  • 2018-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多