Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用XML和DTD将XML转换为对象_C#_.net_Xml_Dtd_Xmlserializer - Fatal编程技术网

C# 使用XML和DTD将XML转换为对象

C# 使用XML和DTD将XML转换为对象,c#,.net,xml,dtd,xmlserializer,C#,.net,Xml,Dtd,Xmlserializer,我有一个XML文件: <?xml version="1.0"?> <!DOCTYPE report SYSTEM "01.dtd" [ <!ENTITY parameter "blablabla"> ]> <report xmlns="http://tempuri.org/report" details="Something is described

我有一个XML文件:

<?xml version="1.0"?>
<!DOCTYPE report SYSTEM "01.dtd" [
    <!ENTITY parameter "blablabla"> 
]>

<report xmlns="http://tempuri.org/report"
  details="Something is described &parameter;"
></report>

我曾尝试将此XML解析为对象,但在details属性中进行反序列化后,我得到以下结果:“Something is description¶meter;”

但我想得到这样的结果:“有些东西被描述成废话”

我的代码如下:

class Program
{
    static void Main(string[] args)
    {
        ReadXMLwithDTD();
    }

    public static void ReadXMLwithDTD()
    {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.XmlResolver = new XmlUrlResolver();
        settings.ValidationType = ValidationType.DTD;
        settings.DtdProcessing = DtdProcessing.Parse;
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
        settings.IgnoreWhitespace = true;

        var files = Directory.GetFiles("../../../App_data/include/", "01.xml", SearchOption.AllDirectories);

        foreach (var file in files)
        {
            XmlDocument xmlDoc = new XmlDocument();

            using (StringReader sr = new StringReader(file))
            using (XmlReader reader = XmlReader.Create(sr, settings))
            {
                xmlDoc.Load(file);
            }

            report r = DeserializeToObject<report>(xmlDoc.OuterXml);
        }

        Console.ReadLine();
    }

    public static T DeserializeToObject<T>(string xml) where T : class
    {
        System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(T));

        MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(xml));

        return (T)ser.Deserialize(memStream);
    }

    private static void ValidationCallBack(object sender, ValidationEventArgs e)
    {
        if (e.Severity == XmlSeverityType.Warning)
            Console.WriteLine("Warning: Matching schema not found.  No validation occurred." + e.Message);
        else // Error
            Console.WriteLine("Validation error: " + e.Message);
    }
}
类程序
{
静态void Main(字符串[]参数)
{
ReadXMLwithDTD();
}
公共静态void ReadXMLwithDTD()
{
XmlReaderSettings设置=新建XmlReaderSettings();
settings.XmlResolver=新的XmlUrlResolver();
settings.ValidationType=ValidationType.DTD;
settings.DtdProcessing=DtdProcessing.Parse;
settings.ValidationEventHandler+=新的ValidationEventHandler(ValidationCallBack);
settings.IgnoreWhitespace=true;
var files=Directory.GetFiles(“../../../App_data/include/”,“01.xml”,SearchOption.AllDirectories);
foreach(文件中的var文件)
{
XmlDocument xmlDoc=新的XmlDocument();
使用(StringReader sr=新的StringReader(文件))
使用(XmlReader=XmlReader.Create(sr,设置))
{
加载(文件);
}
报告r=反序列化对象(xmlDoc.OuterXml);
}
Console.ReadLine();
}
公共静态T反序列化对象(字符串xml),其中T:class
{
System.Xml.Serialization.XmlSerializer ser=new System.Xml.Serialization.XmlSerializer(typeof(T));
MemoryStream memStream=新的MemoryStream(Encoding.UTF8.GetBytes(xml));
返回(T)序列反序列化(memStream);
}
私有静态void ValidationCallBack(对象发送方,ValidationEventArgs e)
{
如果(e.Severity==XmlSeverityType.Warning)
Console.WriteLine(“警告:未找到匹配的架构。未进行任何验证。”+e.Message);
else//错误
Console.WriteLine(“验证错误:+e.Message”);
}
}

我应该更改什么?

无需将XML加载到中间
XmlDocument
中。您可以通过
XmlSerializer
在反序列化过程中扩展实体,只要将配置为的
XmlReader
传递给序列化程序

也就是说,如果我将您的反序列化代码概括如下:

public static partial class XmlSerializationHelper
{
    public static T LoadFromXmlWithDTD<T>(string filename, XmlSerializer serial = default, ValidationEventHandler validationCallBack = default)
    {
        var settings = new XmlReaderSettings
        {
            // This will throw an exception if uncommented:
            //   System.Xml.XmlException: An error has occurred while opening external DTD 'file:///app/01.dtd': Could not find file '/app/01.dtd'
            // XmlResolver = new XmlUrlResolver(), 
            DtdProcessing = DtdProcessing.Parse,
            IgnoreWhitespace = true,
        };
        settings.ValidationEventHandler += validationCallBack;
        serial = serial ?? new XmlSerializer(typeof(T));
        using (var reader = XmlReader.Create(filename, settings))
            return (T)serial.Deserialize(reader);
    }
}
var report = XmlSerializationHelper.LoadFromXmlWithDTD<report>(filename, validationCallBack: ValidationCallBack);
注:

  • 您可能需要设置:

    此属性允许您减轻拒绝服务攻击,攻击者通过扩展实体提交试图超过内存限制的XML文档。通过限制扩展实体产生的字符,可以检测攻击并可靠地恢复

  • 在以下代码中:

    using (StringReader sr = new StringReader(file)) 
    using (XmlReader reader = XmlReader.Create(sr, settings))
    {
        xmlDoc.Load(file);
    }
    
    创建一个
    XmlReader
    ,它使用
    StringReader
    解析文件名
    file
    ,就像它是一个XML字符串而不是文件名字符串一样——然后忽略您创建的读取器,并使用
    xmlDoc.load(file)直接按名称加载文件内容。这似乎忽略了刚刚构建的
    设置
    ,可能是导致bug的直接原因

  • 如果未找到指定的外部dtd文件(未包含在您的问题中),取消注释
    XmlResolver=new XmlUrlResolver()
    将导致引发异常
    无法找到文件'/app/01.dtd'


演示小提琴。

LINQ to XML将为您自动扩展实体引用,请参阅。这是你想要的吗?您的问题甚至不清楚为什么要加载到中间
XmlDocument
,然后反序列化它的OuterXml。
using (StringReader sr = new StringReader(file)) 
using (XmlReader reader = XmlReader.Create(sr, settings))
{
    xmlDoc.Load(file);
}