C# XmlDocument加载XML报意外XML声明错误问题咨询
问题根因
报错的直接原因是生成的XML文件存在多处XML声明,具体触发点有两个:
- 首次写入公司信息时,
StreamWriter使用了追加模式(构造函数第二个参数传了true),如果目标路径下已存在同名XML文件,序列化公司信息时会直接在旧文件末尾追加带XML声明的新内容,直接生成重复声明。 - 追加机器数据的函数中,你配置的
OmitXmlDeclaration = true没有生效。你直接将StreamWriter实例传给了序列化方法,没有通过XmlWriter加载你定义的写入配置,因此每次序列化机器数据时,都会自动输出完整的XML声明,每追加一台设备就多一个声明头。 - 额外隐患:就算移除了多余声明,当前逐段拼接序列化片段的写法还会导致XML存在多个平级根节点,后续加载时依然会抛出格式错误。标准XML格式仅允许存在一个根节点。
临时修复方案(针对现有代码逻辑修改)
如果要保留当前逐段写入的逻辑,做两处修改即可解决重复声明问题:
- 修改保存按钮中首次写入公司信息的逻辑,创建新文件时使用覆盖模式,避免旧文件内容残留:
// 将StreamWriter构造函数的第二个参数从true改为false,首次写入采用覆盖模式 using (var writer = new StreamWriter(Path.Combine(appData, $"{txbCompany.Text}_{txbSiteName.Text}.xml"), false)) { x.Serialize(writer, companyProfile); }
- 修改追加机器数据的函数,通过
XmlWriter加载配置,让省略XML声明的设置真正生效,同时去掉多余的命名空间属性:
private void AppendMachineData(MachineProfile machineProfile, string fileName) { System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(MachineProfile)); var settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = true; using (var streamWriter = new StreamWriter(fileName, true)) // 用配置好的XmlWriter包裹流,写入规则才会生效 using (var xmlWriter = XmlWriter.Create(streamWriter, settings)) { // 清空默认命名空间,避免生成多余的xmlns属性 XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); x.Serialize(xmlWriter, machineProfile, ns); } }
注意:该方案仅解决重复XML声明问题,依然存在多根节点的格式隐患,不推荐长期使用。
推荐实现方案(从根源避免格式问题)
不要采用逐段追加序列化片段的方式生成XML,这类写法非常容易生成不符合规范的XML文件。正确的做法是先组装完整的待存储数据对象,一次性完成序列化写入,全程只生成一个XML声明、一个根节点:
- 定义统一的存储根模型,包含公司信息和所有机器数据:
[Serializable] public class ClientStoreModel { public CompanyProfile CompanyInfo { get; set; } public List<MachineProfile> MachineList { get; set; } }
- 保存时组装完整数据,一次性写入文件,完全不需要追加操作:
// 替换原来逐段序列化写入的逻辑 ClientStoreModel saveData = new ClientStoreModel(); saveData.CompanyInfo = companyProfile; saveData.MachineList = dsMachineProfile.Cast<MachineProfile>().ToList(); System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ClientStoreModel)); using (var writer = new StreamWriter(Path.Combine(appData, $"{txbCompany.Text}_{txbSiteName.Text}.xml"), false)) { serializer.Serialize(writer, saveData); }
- 读取文件时直接反序列化为
ClientStoreModel对象即可,不需要手动通过XmlDocument逐节点解析,代码更简洁,也不会出现XML格式解析错误。
内容的提问来源于stack exchange,提问作者ElectricRay81
相关产品推荐
相关产品推荐

