如何在不获取xmlns =“…”的情况下将对象序列化为XML?


109

有没有一种方法可以让我在.NET中序列化一个对象,而XML命名空间也不会自动序列化呢?似乎默认情况下,.NET认为应该包含XSI和XSD名称空间,但是我不希望它们出现在其中。

Answers:


142

啊...没关系。提出问题后,总是会找到答案。我正在序列化的对象obj已经并且已经定义。将具有单个空名称空间的XMLSerializerNamespace添加到集合中就可以了。

在VB中是这样的:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using

在C#中是这样的:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);

12
我在VB中进行了尝试,xsi和xsd属性消失了,但是出现了诸如xmlns:q12 =,d3p1:type和xmlns:d3p1之类的属性。
2013年

16
我尝试了C#版本,它删除了xsi和xsd,但在所有XML标记名称中添加了q1:前缀,这是我不想要的。似乎C#示例不完整,引用了myXmlTextWriter,我认为需要使用与VB示例相同的方式进行初始化。
redtetrahedron

1
@redtetrahedron您找到摆脱q1垃圾的方法了吗?
暗恋

参考答案stackoverflow.com/questions/31946240/...,如果Q1加入空白命名空间
aniruddha

20

如果您想摆脱多余的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema",但仍保留自己的名称空间xmlns="http://schemas.YourCompany.com/YourSchema/",则使用与上述相同的代码,但要进行以下简单更改:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   

13

如果要删除名称空间,可能还希望删除版本,为了节省您的搜索,我已经添加了该功能,因此下面的代码可以做到。

我还将其包装在通用方法中,因为我正在创建非常大的xml文件,这些文件太大而无法在内存中进行序列化,因此我将输出文件分解并以较小的“块”进行序列化:

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }

请注意,StringWriter默认为UTF-16编码,这可能会导致下游的反序列化问题。using (var reader = XmlReader.Create(stream)){ reader.Read(); }这将引发异常,因为声明将其声明为UTF-16,而内容实际上被编写为UTF-8。 System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan

要解决此问题并仍然使用XmlReader,可以使用var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);True。如果找到,则true将使用BOM,否则将提供您提供的默认值。
Tyler StandishMan

9

我建议这个辅助类:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)


很好的答案:)我也添加了此line stream.Position = 0; 并在我的解决方案中返回了整个流。.按预期工作-删除了所有减速标签
-ymz

仅将名称空间参数添加到序列化程序调用中对我来说可以删除默认名称空间。写作new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty}),而不是new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})在于它的代码故意清晰的方式,在我看来。
Suncat2000

5

如果您无法摆脱每个元素的额外xmlns属性,那么从生成的类序列化为xml时(例如:使用xsd.exe时),那么您将得到以下内容:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

然后我将与您分享对我有用的东西(以前的答案和我在这里找到的东西的组合

显式设置所有不同的xmlns,如下所示:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

然后将其传递给序列化

serializer.Serialize(writer, object, xmlns);

您将在root元素中声明了三个名称空间,而在其他元素中将不再需要生成它们的相应名称前缀

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...

0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.