C# 如何在使用Xmlnclude后删除不需要的属性?

C# 如何在使用Xmlnclude后删除不需要的属性?,c#,xml-namespaces,xmlserializer,C#,Xml Namespaces,Xmlserializer,我正在尝试序列化为以下XML: ... <ManifestHeader> <Party Role="CHARGE"> <f:Name>Name1</f:Name> ... </Party> <Party Role="SENDER"> <Name>Name2</Name> ... </Party>

我正在尝试序列化为以下XML:

...
<ManifestHeader>
    <Party Role="CHARGE">
        <f:Name>Name1</f:Name>
        ...
    </Party>
    <Party Role="SENDER">
        <Name>Name2</Name>
        ...
    </Party>
</ManifestHeader>
...
我使用
xmlclude
如下:

[XmlInclude(typeof(PickupParty))]
[XmlInclude(typeof(SenderParty))]
在序列化程序中,我使用自定义命名空间:

serialiser.Serialize(file, this, nameSpace);
有什么想法吗


编辑


我在发布我的问题之前退房了。首先,我使用的是
XmlSerializer
而不是
DataContractSerializer
,其次,我成功地为所有对象设置了名称空间,但
xmlclude
中包含的对象除外。因此这个问题就出现了。

这是一个解决办法,而不是真正的解决方案

我没有使用基类和子类,而是使用了一个大类,这样就不需要
xmlclude
,从而避免了不需要的属性(
d4p1:type
xmlns:d4p1

我使用的单个大类基本上具有前面子类的所有属性。根据类的角色,只使用属性的子集


这是相当丑陋的,所以如果有人有一个适当的解决方案,这将是卑鄙的

这是一种变通方法,不是真正的解决方案

我没有使用基类和子类,而是使用了一个大类,这样就不需要
xmlclude
,从而避免了不需要的属性(
d4p1:type
xmlns:d4p1

我使用的单个大类基本上具有前面子类的所有属性。根据类的角色,只使用属性的子集

这是相当丑陋的,所以如果有人有一个适当的解决方案,这将是卑鄙的

该属性通常带有前缀“
xsi:type
”,是多态元素显式声明其类型的标准方式
XmlSerializer
将它用于--并因此在序列化期间写入它以供以后使用

没有简单的方法可以抑制类型的输出,同时为每个多态类型保留相同的元素名。(如果
AParty
的每个子类都有不同的元素名称,这将很容易,但您没有)。最好的选择是让
ManifestHeader
实现。您不能完全指定<代码>清单/ADDER < /C> >,请考虑下面的例子:

[XmlRoot("ManifestHeader", Namespace = ManifestHeader.XmlNamespace)]
public class ManifestHeader : IXmlSerializable
{
    public const string XmlNamespace = "MyNamespace";

    public static XmlSerializerNamespaces GetXmlSerializerNamespaces()
    {
        var ns = new XmlSerializerNamespaces();
        ns.Add("", ManifestHeader.XmlNamespace);
        return ns;
    }

    // Some example properties

    public string AProperty { get; set; }

    public string ZProperty { get; set; }

    // The list of parties.

    public AParty[] Parties { get; set; }

    #region IXmlSerializable Members

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        throw new NotImplementedException();
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        var ns = GetXmlSerializerNamespaces();
        writer.WriteElementString("ZProperty", ZProperty);
        foreach (var value in Parties)
        {
            XmlSerializationHelper.SerializeElementTo(value, "Party", ManifestHeader.XmlNamespace, writer, ns);
        }
        writer.WriteElementString("AProperty", AProperty);
    }
    #endregion
}

public abstract class AParty
{
    [XmlAttribute]
    public abstract string Role { get; set; } // Returns a constant string; setter does nothing.
}
这将手动序列化
ManifestHeader
(如果有)的属性,循环遍历
参与方
数组的元素,并序列化每个元素,将它们的元素名称替换为
“参与方”

它使用以下帮助器方法。请注意,如果要使用构造函数重写根元素名称,则必须:

产生:


Z属性
事件的发送者
符合事实的
另一个发件人名称
还有另一个发送者的名字
符合事实的
财产
该属性通常带有前缀“
xsi:type
”,是多态元素显式声明其类型的标准方法
XmlSerializer
将它用于--并因此在序列化期间写入它以供以后使用

没有简单的方法可以抑制类型的输出,同时为每个多态类型保留相同的元素名。(如果
AParty
的每个子类都有不同的元素名称,这将很容易,但您没有)。最好的选择是让
ManifestHeader
实现。您不能完全指定<代码>清单/ADDER < /C> >,请考虑下面的例子:

[XmlRoot("ManifestHeader", Namespace = ManifestHeader.XmlNamespace)]
public class ManifestHeader : IXmlSerializable
{
    public const string XmlNamespace = "MyNamespace";

    public static XmlSerializerNamespaces GetXmlSerializerNamespaces()
    {
        var ns = new XmlSerializerNamespaces();
        ns.Add("", ManifestHeader.XmlNamespace);
        return ns;
    }

    // Some example properties

    public string AProperty { get; set; }

    public string ZProperty { get; set; }

    // The list of parties.

    public AParty[] Parties { get; set; }

    #region IXmlSerializable Members

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        throw new NotImplementedException();
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        var ns = GetXmlSerializerNamespaces();
        writer.WriteElementString("ZProperty", ZProperty);
        foreach (var value in Parties)
        {
            XmlSerializationHelper.SerializeElementTo(value, "Party", ManifestHeader.XmlNamespace, writer, ns);
        }
        writer.WriteElementString("AProperty", AProperty);
    }
    #endregion
}

public abstract class AParty
{
    [XmlAttribute]
    public abstract string Role { get; set; } // Returns a constant string; setter does nothing.
}
这将手动序列化
ManifestHeader
(如果有)的属性,循环遍历
参与方
数组的元素,并序列化每个元素,将它们的元素名称替换为
“参与方”

它使用以下帮助器方法。请注意,如果要使用构造函数重写根元素名称,则必须:

产生:


Z属性
事件的发送者
符合事实的
另一个发件人名称
还有另一个发送者的名字
符合事实的
财产

@erem可能重复我不认为它是重复的,请看我的编辑。你还需要反序列化吗?@dbc-Nah,只需要序列化。你为什么要删除这些属性?可能重复的@erem我不认为它是重复的,请看我的编辑。你还需要反序列化吗?@dbc-Nah,只需要序列化。为什么要删除这些属性?非常感谢您提供的详细答案!我已经尝试在您自己的项目中运行您的解决方案,但行
var xml=manifest.GetXml(ManifestHeader.GetXmlSerializerNamespaces())我收到一个错误:
错误1'XmlSerialization.ManifestHeader'不包含'GetXml'的定义,并且找不到接受'XmlSerialization.ManifestHeader'类型的第一个参数的扩展方法'GetXml'(是否缺少using指令或程序集引用?)C:\ws\xmlserialization\xmlserialization\Program.cs 61 32 xmlserialization
。有什么想法吗?@Felix-这是一种扩展方法,我用来序列化为XML进行测试。包括在内。非常感谢您的详细回答!我已经尝试在您自己的项目中运行您的解决方案,但行
var xml=manifest.GetXml(ManifestHeader.GetXmlSerializerNamespaces())我收到一个错误:
错误1'XmlSerialization.ManifestHeader'不包含'GetXml'的定义,并且找不到接受'XmlSerialization.ManifestHeader'类型的第一个参数的扩展方法'GetXml'(是否缺少using指令或程序集引用?)C:\ws\xmlserialization\xmlserialization\Program.cs 61 32 xmlserialization
。有什么想法吗?@Felix-这是一种扩展方法,我用来序列化为XML进行测试。包括在内。
[XmlRoot("ManifestHeader", Namespace = ManifestHeader.XmlNamespace)]
public class ManifestHeader : IXmlSerializable
{
    public const string XmlNamespace = "MyNamespace";

    public static XmlSerializerNamespaces GetXmlSerializerNamespaces()
    {
        var ns = new XmlSerializerNamespaces();
        ns.Add("", ManifestHeader.XmlNamespace);
        return ns;
    }

    // Some example properties

    public string AProperty { get; set; }

    public string ZProperty { get; set; }

    // The list of parties.

    public AParty[] Parties { get; set; }

    #region IXmlSerializable Members

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        throw new NotImplementedException();
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        var ns = GetXmlSerializerNamespaces();
        writer.WriteElementString("ZProperty", ZProperty);
        foreach (var value in Parties)
        {
            XmlSerializationHelper.SerializeElementTo(value, "Party", ManifestHeader.XmlNamespace, writer, ns);
        }
        writer.WriteElementString("AProperty", AProperty);
    }
    #endregion
}

public abstract class AParty
{
    [XmlAttribute]
    public abstract string Role { get; set; } // Returns a constant string; setter does nothing.
}
public static class XmlSerializationHelper
{
    public static void SerializeElementTo<T>(T value, string elementName, string elementNamespace, XmlWriter writer, XmlSerializerNamespaces ns)
    {
        var serializer = XmlSerializerRootAttributeCache.DemandSerializer(value.GetType(), elementName, elementNamespace);
        serializer.Serialize(writer, value, ns);
    }

    public static string GetXml<T>(this T obj)
    {
        return GetXml(obj, false);
    }

    public static string GetXml<T>(this T obj, bool omitNamespace)
    {
        return GetXml(obj, new XmlSerializer(obj.GetType()), omitNamespace);
    }

    public static string GetXml<T>(this T obj, XmlSerializer serializer)
    {
        return GetXml(obj, serializer, false);
    }

    public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
    {
        XmlSerializerNamespaces ns = null;
        if (omitStandardNamespaces)
        {
            ns = new XmlSerializerNamespaces();
            ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
        }
        return GetXml(obj, serializer, ns);
    }

    public static string GetXml<T>(T obj, XmlSerializer serializer, XmlSerializerNamespaces ns)
    {
        using (var textWriter = new StringWriter())
        {
            var settings = new XmlWriterSettings() { Indent = true, IndentChars = "    " }; // For cosmetic purposes.
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                serializer.Serialize(xmlWriter, obj, ns);
            return textWriter.ToString();
        }
    }

    public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns)
    {
        return GetXml(obj, new XmlSerializer(obj.GetType()), ns);
    }
}

public static class XmlSerializerRootAttributeCache
{
    readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
    readonly static object padlock = new object();

    static XmlSerializerRootAttributeCache()
    {
        cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
    }

    static XmlSerializer CreateSerializer(Type rootType, string rootName, string rootNamespace)
    {
        return new XmlSerializer(rootType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
    }

    public static XmlSerializer DemandSerializer(Type rootType, string rootName, string rootNamespace)
    {
        var key = Tuple.Create(rootType, rootName, rootNamespace);
        lock (padlock)
        {
            XmlSerializer serializer;
            if (!cache.TryGetValue(key, out serializer))
                serializer = cache[key] = CreateSerializer(rootType, rootName, rootNamespace);
            return serializer;
        }
    }
}
[XmlRoot("ChargeParty", Namespace = ManifestHeader.XmlNamespace)]
[XmlType("ChargeParty", Namespace = ManifestHeader.XmlNamespace)]
public sealed class ChargeParty : AParty
{
    [XmlAttribute]
    public override string Role
    {
        get
        {
            return "CHARGE";
        }
        set
        {
        }
    }

    public bool IsCharging { get; set; }
}

[XmlRoot("SenderParty", Namespace = ManifestHeader.XmlNamespace)]
[XmlType("SenderParty", Namespace = ManifestHeader.XmlNamespace)]
public sealed class SenderParty : AParty
{
    [XmlAttribute]
    public override string Role
    {
        get
        {
            return "SENDER";
        }
        set
        {
        }
    }

    public string SenderName { get; set; }
}

public static class TestClass
{
    public static void Test()
    {
        var manifest = new ManifestHeader
        {
            AProperty = "A property",
            ZProperty = "Z Property",
            Parties = new AParty[] { new SenderParty { SenderName = "Sender Name" }, new ChargeParty { IsCharging = true }, new SenderParty { SenderName = "Another Sender Name" }, new SenderParty { SenderName = "Yet Another Sender Name" }, new ChargeParty { IsCharging = false } }
        };
        var xml = manifest.GetXml(ManifestHeader.GetXmlSerializerNamespaces());
        Debug.WriteLine(xml);
    }
}
<ManifestHeader xmlns="MyNamespace">
    <ZProperty>Z Property</ZProperty>
    <Party Role="SENDER">
        <SenderName>Sender Name</SenderName>
    </Party>
    <Party Role="CHARGE">
        <IsCharging>true</IsCharging>
    </Party>
    <Party Role="SENDER">
        <SenderName>Another Sender Name</SenderName>
    </Party>
    <Party Role="SENDER">
        <SenderName>Yet Another Sender Name</SenderName>
    </Party>
    <Party Role="CHARGE">
        <IsCharging>true</IsCharging>
    </Party>
    <AProperty>A property</AProperty>
</ManifestHeader>