使用F# XmlProvider更新XML后输出命名空间格式错误如何解决
问题根因
- 第一种修改方式直接操作原XML解析生成的
XElement节点,原节点树已经保留了根节点上声明的所有命名空间前缀映射,序列化时会自动复用前缀,因此输出格式符合预期。 - 第二种修改方式调用
XmlProvider生成的强类型构造函数创建全新的Invoice实例,新生成的节点树没有继承原XML的全局命名空间前缀映射,序列化时会为每个节点单独输出完整命名空间定义,不会复用ehf、cbc、cac这类前缀,因此出现格式错误。
解决方案
推荐优先使用基于原节点修改的方案,无需手动处理命名空间映射,即可适配替换全部发票行这类复杂更新操作,示例代码如下:
// 假设你已经生成了需要替换的新发票行数组 newInvoiceLines let root = invoice.XElement // 移除所有原有发票行节点 root.Descendants(cac + "InvoiceLine") |> Seq.iter (fun node -> node.Remove()) // 批量添加新发票行节点 for newLine in newInvoiceLines do root.Add(newLine.XElement) // 输出结果和原XML格式完全一致 printfn $"{invoice |> string}"
如果你的场景需要完全新建Invoice实例而非修改原有实例,可以手动为新生成的根节点补充命名空间前缀声明,示例代码如下:
let line = invoice.InvoiceLines.[0] let newLine = Invoice.InvoiceLine( "New id", line.Note, line.OrderLineReference, line.Item ) let changedInvoice = Invoice.Invoice( invoice.Id, [|newLine|] ) // 手动补充命名空间前缀映射 let root = changedInvoice.XElement root.Add(XAttribute(XNamespace.Xmlns + "cbc", cbc.NamespaceName)) root.Add(XAttribute(XNamespace.Xmlns + "cac", cac.NamespaceName)) root.Add(XAttribute(XNamespace.Xmlns + "ext", "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2")) root.Add(XAttribute(XNamespace.Xmlns + "ehf", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2")) // 修正根节点的带前缀名称 root.Name <- XName.Get("Invoice", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2") // 输出格式符合要求 printfn $"{changedInvoice |> string}"
内容的提问来源于stack exchange,提问作者Espen Brun
相关产品推荐
相关产品推荐

