

新闻资讯
技术学院XDocument 默认不支持添加 DTD,因其基于轻量级 LINQ to XML,为安全与简化模型而忽略 DTD 解析和序列化;需用 XmlWriter 配合 DoctypePublic/DoctypeSystem 输出简单 DOCTYPE,复杂内联 DTD 则须改用 XmlDocument。
C# 中的 XDocument 默认不支持直接添加 DTD(Document Type Definition)声明,因为 XDocument 基于 LINQ to XML,其设计目标是轻量、符合 W3C XML 1.0 核心规范,而DTD 属于已逐步被弃用的旧式 XML 特性,且 LINQ to XML 明确不提供对 DTD 的解析或序列化支持。
Microsoft 官方文档明确指出:XDocument 在加载或保存时会忽略 DTD;调用 Save() 或 ToString() 时,DTD 不会被输出。这是出于安全(如防止 XXE 攻击)和简化模型的考虑。
XDocument 的 Declaration 属性仅支持 XDeclaration(即 XML 声明,如 ),不包含 DTD..> 字符串会导致解析失败或被自动过滤若必须生成带 DTD 的 XML 字符串(例如对接遗留系统),可借助 XmlWriter 配合自定义设置,在写入根元素前显式写出 DTD 行:
var doc = new XDocument(
new XElement("root",
new XElement("child", "content")
)
);
using (var stringWriter =
new StringWriter())
using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings
{
OmitXmlDeclaration = false,
Indent = true,
DoctypeSystem = "my.dtd", // 可选:SYSTEM 公共 ID
DoctypePublic = "-//MyOrg//DTD MyDoc 1.0//EN" // 可选:PUBLIC ID
}))
{
// 手动写入 DOCTYPE(XmlWriter 会在 WriteStartDocument 后自动加)
writer.WriteStartDocument();
// 注意:DoctypePublic/DoctypeSystem 设置会触发 XmlWriter 自动写入 DOCTYPE 行
doc.Root?.WriteTo(writer);
writer.Flush();
string xmlWithDtd = stringWriter.ToString();
// 输出示例:
//
//
// content
}
⚠️ 注意:此方式依赖 XmlWriter 的 DoctypePublic / DoctypeSystem 设置,仅适用于简单 PUBLIC/SYSTEM 引用;无法写入内联 DTD(如包含 ENTITY 或 ATTLIST 定义),因为 XmlWriter 不支持嵌入式 DTD 内容。
需要完整内联 DTD?改用 XmlDocument
如果业务强依赖内联 DTD(例如定义实体 或元素约束),应切换到传统 XmlDocument:
XmlDocument 支持 CreateDocumentType() 方法创建 XmlDocumentType 节点AppendChild(docType) 将 DTD 插入文档开头示例:
var doc = new XmlDocument();
var docType = doc.CreateDocumentType("root", "-//MyOrg//DTD MyDoc 1.0//EN", "my.dtd", null);
doc.AppendChild(docType);
var root = doc.CreateElement("root");
root.AppendChild(doc.CreateElement("child")).InnerText = "content";
doc.AppendChild(root);
string xml = doc.OuterXml; // 包含完整 DOCTYPE
对于绝大多数现代场景,避免使用 DTD —— 改用 XML Schema(XSD)或 JSON Schema 更安全、更易维护。若仅需兼容性输出简单 DOCTYPE 声明:
XmlWriter + DoctypePublic/DoctypeSystem(轻量、可控)XDocument.Save() 直接输出,它不会保留 DTDXmlDocument 是唯一可靠选择XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit),防范 XXE