从 XML 声明片段获取 XML 编码:部分内容解析不支持 XmlDeclaration

Posted

技术标签:

【中文标题】从 XML 声明片段获取 XML 编码:部分内容解析不支持 XmlDeclaration【英文标题】:Obtaining the XML encoding from an XML declaration fragment: XmlDeclaration is not supported for partial content parsing 【发布时间】: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。如果有其他方法可以做到这一点,我愿意接受。

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

【问题讨论】:

【参考方案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);
        

【讨论】:

以上是关于从 XML 声明片段获取 XML 编码:部分内容解析不支持 XmlDeclaration的主要内容,如果未能解决你的问题,请参考以下文章

使用非utf-8编码在Python中解析XML

第1天 XML和DTDschema约束

web.xml配置

web.xml配置

web.xml配置详解

web.xml配置详解