【问题标题】:Obtaining the XML encoding from an XML declaration fragment: XmlDeclaration is not supported for partial content parsing从 XML 声明片段获取 XML 编码:部分内容解析不支持 XmlDeclaration
【发布时间】:2016-03-21 11:28:27
【问题描述】:

我正在编写一些代码来读取包含 XML 声明的 XML 片段,例如<?xml version="1.0" encoding="utf-8"?> 并解析编码。从MSDN,我应该可以这样做:

var nt = new NameTable();
var mgr = new XmlNamespaceManager(nt);
var context = new XmlParserContext(null, mgr, null, XmlSpace.None);

var reader = new System.Xml.XmlTextReader(@"<?xml version=""1.0"" encoding=""UTF-8""?>", 
    System.Xml.XmlNodeType.XmlDeclaration, context);

但是,我在调用 System.Xml.XmlTextReader 构造函数时收到了一个 System.Xml.XmlException 并带有一条错误消息:

部分内容不支持 XmlNodeType XmlDeclaration 解析。

我已经在引号中搜索了这个错误 - 找到的结果恰好为零(编辑:现在有一个结果:这篇文章) - 并且没有引号,这不会产生任何有用的信息。我还查看了MSDN for the XmlNodeType,并没有说明它不受支持。

我在这里缺少什么? 如何从 XML 声明片段中获取 XmlTextReader 实例

注意,我的目标只是确定部分构建的 XML 文档的编码,我假设它至少包含一个声明节点;因此,我正在尝试获取reader.Encoding。如果有其他方法可以做到这一点,我愿意接受。

目前,我正在使用正则表达式手动解析声明,这不是最好的方法。

【问题讨论】:

    标签: c# .net xml parsing encoding


    【解决方案1】:

    更新:从 XML 文档或 XML 片段中获取编码:

    这是一种无需使用假根即可获得编码的方法,使用XmlReader.Create

    private static string GetXmlEncoding(string xmlString)
    {
        if (string.IsNullOrWhiteSpace(xmlString)) throw new ArgumentException("The provided string value is null or empty.");
    
        using (var stringReader = new StringReader(xmlString))
        {
            var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
    
            using (var xmlReader = XmlReader.Create(stringReader, settings))
            {
                if (!xmlReader.Read()) throw new ArgumentException(
                    "The provided XML string does not contain enough data to be valid XML (see https://msdn.microsoft.com/en-us/library/system.xml.xmlreader.read)");
    
                var result = xmlReader.GetAttribute("encoding");
                return result;
            }
        }
    }
    

    这是输出,带有完整和片段的 XML:

    如果你想要System.Text.Encoding,你可以修改代码如下:

        private static Encoding GetXmlEncoding(string xmlString)
        {
            using (StringReader stringReader = new StringReader(xmlString))
            {
                var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
    
                var reader = XmlReader.Create(stringReader, settings);
                reader.Read();
    
                var encoding = reader.GetAttribute("encoding");
    
                var result = Encoding.GetEncoding(encoding);
                return result;
            }
        }
    

    旧答案:

    正如您提到的,XmlTextReader's Encoding-property 包含编码。

    这是一个完整的控制台应用程序源代码,希望对您有用:

    class Program
    {
        static void Main(string[] args)
        {
            var asciiXML = @"<?xml version=""1.0"" encoding=""ASCII""?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>";
            var utf8XML = @"<?xml version=""1.0"" encoding=""UTF-8""?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>";
    
            var asciiResult = GetXmlEncoding(asciiXML);
            var utfResult = GetXmlEncoding(utf8XML);
    
            Console.WriteLine(asciiResult);
            Console.WriteLine(utfResult);
    
            Console.ReadLine();
        }
        private static Encoding GetXmlEncoding(string s)
        {
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(s));
    
            using (var xmlreader = new XmlTextReader(stream))
            {
                xmlreader.MoveToContent();
                var encoding = xmlreader.Encoding;
    
                return encoding;
            }
        }
    }
    

    这是程序的输出:

    如果您知道 XML 只包含声明,也许您可​​以添加一个空根?比如:

            var fragmentResult = GetXmlEncoding(xmlFragment + "<root/>");
    

    【讨论】:

    • 但是如果我只有一个声明片段,即没有其他 XML 正文,这会起作用吗?例如,我只有&lt;?xml version=""1.0"" encoding=""ASCII""?&gt;。根据我的问题:“我正在编写一些代码来读取包含 XML 声明的 XML 片段,例如 "
    • 是的,看,我试过了,我得到“root element is missing”
    • 是的,没错。不是一个理想的解决方案,但是添加“假”根怎么样?例如: var xmlForEncodingParsing = xmlFragment + "/"
    • 添加假根可能是这里唯一的选择。无赖。
    • 我相信你能弄明白,但我更新了我的答案以展示一个假根的例子。
    【解决方案2】:

    晚上好,这是使用 System.Text.Encoding 作为输出的解决方案。 我说的很清楚,一步一步来。

    class Program
    {
        static void Main(string[] args)
        {
            var line = File.ReadLines(YourFileName).First();
            var correctXml = line + "<Root></Root>";
            var xml = XDocument.Parse(correctXml);
            var stringEncoding = xml.Declaration.Encoding;
            var encoding = System.Text.Encoding.GetEncoding(stringEncoding);
        }
    }
    

    【讨论】:

    • 实际上,xml.Declaration.Encodingstring 而不是 System.Text.Encoding。你能添加一些代码来实现吗?
    • 你好 roryap !我更新了解决方案以满足您的要求。
    【解决方案3】:

    也许晚了,但您可以在将以下代码加载到 XmlDocument 后使用它

        static string getEncoding(XmlDocument xml)
        {
            if (xml.FirstChild.NodeType == XmlNodeType.XmlDeclaration)
            {
                return (xml.FirstChild as XmlDeclaration).Encoding;
            }
            return "utf-8";
        }
    

    【讨论】:

      【解决方案4】:

      如果您有一个字节数组作为输入,请尝试以下操作:

      private Encoding getEncoding(byte[] data)
              {
                  XmlReaderSettings settings = new XmlReaderSettings();
                  settings.DtdProcessing = DtdProcessing.Ignore;
                  XmlDocument doc = new XmlDocument();
                  MemoryStream ms = new MemoryStream(data);
                  XmlReader reader = XmlReader.Create(ms, settings);
                  doc.Load(reader);
                  XmlDeclaration declaration = doc.ChildNodes.OfType<XmlDeclaration>().FirstOrDefault();
                  return Encoding.GetEncoding(declaration.Encoding);
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-20
        • 2015-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-25
        • 2011-06-29
        相关资源
        最近更新 更多