【问题标题】:Process XML in C# using external entity file使用外部实体文件在 C# 中处理 XML
【发布时间】:2011-02-09 15:12:49
【问题描述】:

我正在用 C# 处理一个 XML 文件(不包含任何 dtdent 声明),其中包含 éà 等实体。尝试加载 XML 文件时收到以下异常...

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(record);

对未声明实体的引用 'eacute'。

我能够找到正确的 ent 文件 here。我如何告诉XmlDocument 在加载我的 XML 文件时使用这个 ent 文件?

【问题讨论】:

    标签: c# xml special-characters


    【解决方案1】:

    在 .Net 4 之前的框架版本中,您使用 XmlReaderSettings 实例的 ProhibitDtd

    var settings = new XmlReaderSettings();
    
    settings.ProhibitDtd = false;
    
    string DTD = @"<!DOCTYPE doc [
        <!ENTITY % iso-lat1 PUBLIC ""ISO 8879:1986//ENTITIES Added Latin 1//EN//XML""
        ""http://www.oasis-open.org/docbook/xmlcharent/0.3/iso-lat1.ent"">
        %iso-lat1;
        ]> ";
    
    string xml = string.Concat(DTD,"<xml><txt>ren&eacute;</txt></xml>");
    
    XmlDocument xd = new XmlDocument();
    xd.Load(XmlReader.Create(new MemoryStream(
            UTF8Encoding.UTF8.GetBytes(xml)), settings));
    

    从 .Net 4.0 开始,使用您在 XmlTextReader 上设置的值为 DtdProcessing.ParseDtdProcessing 属性。

    XmlDocument xd = new XmlDocument();
    using (var rdr = new XmlTextReader(new StringReader(xml)))
    {
        rdr.DtdProcessing = DtdProcessing.Parse;
        xd.Load(rdr);
    }     
    

    【讨论】:

    • 您的解决方案对我有用。我只需要更改 settings.DtdProcessing = DtdProcessing.Parse;到 settings.ProhibitDtd = false;
    • 好的,很好,ProhibitDtd 在 v4.0 中已被弃用
    • 这很容易产生无效的 XML,所以这是一种幼稚的方法。如果有一个关于 XML 字符串开头的 XML 声明会发生什么?如果有,您的代码会将格式正确的 XML 转换为不再是 XML 的内容。
    • @Nic Gibson 你是绝对正确的。您描述的场景既不适用也不适用于需要一个以上实体集的场景。在这两种情况下,它都会在 xd.Load 上中断。如果有人有兴趣提出一个新问题,我会添加一些额外的安全防护代码来克服 Nic 描述的场景
    【解决方案2】:

    我遇到了同样的问题,不想修改我的 XML(或 DTD),我决定创建自己的 XmlResolver 来动态添加实体。

    我的实现实际上是从配置文件中读取实体,但这应该足以满足您的要求。在此示例中,我将右单大引号转换为撇号。

    class XmlEntityResolver : XmlResolver {
        public override object GetEntity(Uri absoluteUri,
                                         string role,
                                         Type ofObjectToReturn) 
        {
            if (absoluteUri.toString() == "-//MY PUB ID") {
                MemoryStream ms = new MemoryStream();
                StreamWriter sw = new StreamWriter(ms);
                sw.Write("<!ENTITY rsquo \"'\">");
                sw.Flush();
                ms.Position = 0;
                return ms;
            }
            else {
                return base.GetEntity(absoluteUri, role, ofObjectToReturn);
            }
        }
    }
    

    然后,当您声明您的 XmlDocument 时,只需在加载之前设置解析器。

    XmlDocument doc = new XmlDocument();
    doc.XmlResolver = new XmlEntityResolver();
    doc.Load(XML_FILE);
    

    【讨论】:

      【解决方案3】:

      &amp;eacute; 默认不是有效的 XML 实体,而默认是有效的 HTML 实体。

      您需要将 &amp;eacute; 定义为有效的 XML 实体以进行 XML 解析。

      编辑:

      要添加对外部 ent 文件的引用,您需要在 XML 文件本身中执行此操作。将 ent 文件保存到磁盘,并将其放在与正在解析的文档相同的目录中。

      <!ENTITY % stuff SYSTEM "iso-lat1.ent">
      %stuff;
      

      如果您想走不同的路线,请查看ENTITY declaration 上的信息。

      【讨论】:

      • 严格来说并非如此。 &amp;eacute; 实体在 HTML DTD 中定义。它不是由 XML 本身定义的,但这并不意味着它不是 XML——只是没有定义。不过链接很好。假设只有几个实体,将它们复制到内部子集中将是务实的答案。
      【解决方案4】:

      根据this,你必须在文件中引用它们;你不能告诉LoadXml 为你做这件事。

      【讨论】:

        【解决方案5】:

        您的问题已在 2004 年的 MSDN 文章中得到解答......您可以在这里找到它......

        http://msdn.microsoft.com/en-us/library/aa302289.aspx

        【讨论】:

        • 虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
        猜你喜欢
        • 1970-01-01
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-02
        • 2019-11-08
        • 1970-01-01
        • 2022-11-11
        • 1970-01-01
        相关资源
        最近更新 更多