c# - 如何使用 XmlSerializer 在大型文档中插入节点

标签 c# .net xml xsd xmlserializer

我有一个大型 XML 文档,我想使用 XmlSerializer 类插入新元素,这些元素的内容来自使用 xsd.exe 生成的 .NET 类实例。

这是问题 How to deserialize a node in a large document using XmlSerializer 的后续问题,并使用该问题中描述的相同 xsd 和生成的类。

假设在我的示例 XML 中,我想用我的福特汽车换一辆宝马汽车。我尝试了以下代码:

static string XmlContent = @"
    <RootNode xmlns=""http://MyNamespace"">
        <Cars>
        <Car make=""Volkswagen"" />
        <Car make=""Ford"" />
        <Car make=""Opel"" />
        </Cars>
    </RootNode>";

private static void TestWriteMcve()
{
    var doc = new XmlDocument();
    doc.LoadXml(XmlContent);
    var nsMgr = new XmlNamespaceManager(doc.NameTable);
    nsMgr.AddNamespace("myns", "http://MyNamespace");

    var node = doc.DocumentElement.SelectSingleNode("myns:Cars/myns:Car[@make='Ford']", nsMgr);
    var parent = node.ParentNode;
    var carSerializer = new XmlSerializer(typeof(Car));

    using (var writer = node.CreateNavigator().InsertAfter())
    {
        // WriteWhitespace needed to avoid error "WriteStartDocument cannot
        // be called on writers created with ConformanceLevel.Fragment."
        writer.WriteWhitespace("");
        var newCar = new Car { make = "BMW" };
        carSerializer.Serialize(writer, newCar);
    }
    parent.RemoveChild(node);
    Console.WriteLine(parent.OuterXml);
}

我得到的结果接近我想要的:

<Cars xmlns="http://MyNamespace">
  <Car make="Volkswagen" />
  <Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" make="BMW" xmlns="" />
  <Car make="Opel" />
</Cars>

除了添加的元素上所有不需要的 xmlns:... 属性。它们从何而来?我该如何摆脱它们?

最佳答案

中所述Omitting all xsi and xsd namespaces when serializing an object in .NET? XmlSerializer 将在序列化时始终有助于添加 xsixsd 命名空间。如果您不希望这样,则需要调用 Serialize 的重载,其中可以指定所需的初始 namespace ,例如XmlSerializer.Serialize(XmlWriter, Object, XmlSerializerNamespaces) .以下扩展方法可以解决问题:

public static class XmlNodeExtensions
{
    public static XmlNode ReplaceWithSerializationOf<T>(this XmlNode node, T replacement)
    {
        if (node == null)
            throw new ArgumentNullException();
        var parent = node.ParentNode;
        var serializer = new XmlSerializer(replacement == null ? typeof(T) : replacement.GetType());

        using (var writer = node.CreateNavigator().InsertAfter())
        {
            // WriteWhitespace needed to avoid error "WriteStartDocument cannot
            // be called on writers created with ConformanceLevel.Fragment."
            writer.WriteWhitespace("");

            // Set up an appropriate initial namespace.
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(node.GetNamespaceOfPrefix(node.NamespaceURI), node.NamespaceURI);

            // Serialize
            serializer.Serialize(writer, replacement, ns);
        }

        var nextNode = node.NextSibling;
        parent.RemoveChild(node);
        return nextNode;
    }
}

然后按如下方式使用:

var newCar = new Car { make = "BMW" };
var node = doc.DocumentElement.SelectSingleNode("myns:Cars/myns:Car[@make='Ford']", nsMgr);
node = node.ReplaceWithSerializationOf(newCar);
var parent = node.ParentNode;

之后,为 doc 生成的 XML 将是:

<RootNode xmlns="http://MyNamespace">
  <Cars>
    <Car make="Volkswagen" />
    <Car make="BMW" />
    <Car make="Opel" />
  </Cars>
</RootNode>

sample 加工 .Net fiddle .

关于c# - 如何使用 XmlSerializer 在大型文档中插入节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48659674/

相关文章:

c# - UPS API .net 无法解析命名空间 TrackWSSample.TrackWebReference

java - 如何使用导入另一个模式文件的模式文件验证 XML?

c# - 通过数字索引访问 Dictionary.Keys 键

c# - 如何通过 IInterceptionBehavior 吞下异常?

c# - WPF UIElement 刷新错误?

c# - ObserveOn 和 SubscribeOn - 工作完成的地方

java - 如何在 Java 中转义 XML 中的非标准字符?

android - 如何删除android中的标题栏?

c# - 我是 C# 编程新手

c# - 通过 C# redis 客户端连接到 redis 很慢!