【问题标题】:.Net XML Serialization issue.Net XML 序列化问题
【发布时间】:2009-07-08 06:33:10
【问题描述】:

我的困惑是,我正在使用 .Net C# XMLSerializer 序列化自定义定义的类型,使用 XSD 工具从输入的原始 XML 文件生成的 schema/cs 文件。但生成的序列化 XML 文件命名空间与原始 XML 输入文件不同。尤其是从原始的 XML 文件中,Envelope 属于命名空间 soapenv,但在序列化的 XML 文件中,Envelope 属于默认命名空间。有什么想法有什么问题吗?

这是我如何使用 XSD 工具从 XML 输入文件 XMLFile1.xml 为自定义定义类型生成模式文件和 cs 文件,

顺便说一句:XML 文件可以从那里下载,

http://www.mediafire.com/?nwngwzz3gmm

D:\>xsd XMLFile1.xml
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.3038]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'D:\XMLFile1.xsd'.

D:\>xsd XMLFile1.xsd XMLFile1_app1.xsd /classes
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.3038]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'D:\XMLFile1_XMLFile1_app1.cs'.

这是我如何使用 C# 代码序列化文件并输出到 TestOutputFile.xml,

static void Main(string[] args)
{
    Envelope en = new Envelope();
    en.Items = new EnvelopeBody[1];
    en.Items[0] = new EnvelopeBody();
    en.Items[0].QueryResponse = new QueryResponseFaculties[1];
    en.Items[0].QueryResponse[0] = new QueryResponseFaculties();
    en.Items[0].QueryResponse[0].Name = "John";

    XmlSerializer serializer =
     new XmlSerializer(typeof(Envelope));
    TextWriter writer = new StreamWriter("TestOutputFile.xml");

    serializer.Serialize(writer, en);
    writer.Close();

    return;
}

原始的 XML 文件是,

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <QueryResponse xmlns="http://schemas.mycorp.com/test">
      <Faculties>
        <Name>
          John
        </Name>
      </Faculties>
    </QueryResponse>
  </soapenv:Body>
</soapenv:Envelope>

序列化的 XML 文件是,

<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <Body>
    <QueryResponse xmlns="http://schemas.mycorp.com/test">
      <Faculties>
        <Name>John</Name>
      </Faculties>
    </QueryResponse>
  </Body>
</Envelope>

编辑 1:

当前代码是,

static void Main(string[] args)
{
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
    ns.Add("", "http://schemas.mycorp.com/test");
    ns.Add("xsd", "http://www.w3.org/2001/XMLSchema");
    ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    Envelope en = new Envelope();
    en.Items = new EnvelopeBody[1];
    en.Items[0] = new EnvelopeBody();
    en.Items[0].QueryResponse = new QueryResponseFaculties[1];
    en.Items[0].QueryResponse[0] = new QueryResponseFaculties();
    en.Items[0].QueryResponse[0].Name = "John";

    XmlSerializer serializer =
     new XmlSerializer(typeof(Envelope));
    TextWriter writer = new StreamWriter("TestOutputFile.xml");

    serializer.Serialize(writer, en, ns);
    writer.Close();

    return;
}

当前输出(序列化的 XML 文件)是,

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://schemas.mycorp.com/test"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <QueryResponse>
      <Faculties>
        <Name>John</Name>
      </Faculties>
    </QueryResponse>
  </soapenv:Body>
</soapenv:Envelope>

我希望输出是(注意字符串 xmlns="http://schemas.mycorp.com/test" 的位置),

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <QueryResponse xmlns="http://schemas.mycorp.com/test">
      <Faculties>
        <Name>John</Name>
      </Faculties>
    </QueryResponse>
  </soapenv:Body>
</soapenv:Envelope>

提前致谢, 乔治

【问题讨论】:

  • 更新了我的示例以显示它可以使用完整代码
  • 您一直说命名空间位于错误的位置,但是当我运行代码时,我发布的输出完全符合您的要求。我想知道这是否是框架版本的东西;我在 3.5SP1
  • George,您的部分问题是您正在序列化信封和内容。你为什么这样做?你没有调用网络服务吗?

标签: c# .net xml-serialization


【解决方案1】:

您需要使用 XmlSerializerNamespaces 类来设置命名空间,然后在序列化时需要将该 XmlSerializerNamespces 实例与您的对象一起传递。您还需要使用 XmlRoot 和 XmlElement 属性设置类和/或属性的命名空间:

static void Main(string[] args)
{
    Envelope en = new Envelope();
    en.Items = new EnvelopeBody[1];
    en.Items[0] = new EnvelopeBody();
    en.Items[0].QueryResponse = new QueryResponseFaculties[1];
    en.Items[0].QueryResponse[0] = new QueryResponseFaculties();
    en.Items[0].QueryResponse[0].Name = "John";

    XmlSerializer serializer =
     new XmlSerializer(typeof(Envelope));
    TextWriter writer = new StreamWriter("TestOutputFile.xml");

    XmlSerlializerNamespaces xsn = new XmlSerializerNamespaces();
    xsn.Add("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");

    serializer.Serialize(writer, en, xsn);
    writer.Close();

    return;
}

[XmlRoot(Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
class Envelope
{
    // ...
}

【讨论】:

  • 感谢 jrista,我已经尝试了您的解决方案,只剩下一个小问题,即我想从元素 QueryResponse 定义默认命名空间 xmlns="schemas.mycorp.com/test,而不是从顶级元素信封,有什么解决办法吗?
  • 您的解决方案将在序列化输出 XML 文件的顶级 XML 元素中定义所有命名空间。
  • 只需使用 XmlElement 属性为任何属性单独设置命名空间。
  • 对不起 jrista,我想我没有让自己理解或者我误解了你的观点。我认为您的解决方案没有解决我的问题。请参考我原帖的 EDIT 1 部分,其中包含序列化文件的当前结果和我预期的输出序列化文件。有什么解决办法吗?
【解决方案2】:

它们不是可以互换的吗?一种是使用xmlns 设置元素的命名空间,另一种是xmlns:soapenv 别名-但含义相同,IMO 的第二个版本更简洁。

XmlSerializerNamespaces 类可以解决这个问题;完整示例:

using System;
using System.Xml.Serialization;
[XmlRoot(Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope {
    public Body Body { get; set; }
}
public class Body {
    [XmlElement(Namespace="http://schemas.mycorp.com/test")]
    public QueryResponse QueryResponse { get; set; }
}
public class QueryResponse {
    public Faculties Faculties { get; set; }
}
public class Faculties {
    public string Name { get; set; }
}
static class Program {
    static void Main() {
        XmlSerializer ser = new XmlSerializer(typeof(Envelope));
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        ns.Add("xsd", "http://www.w3.org/2001/XMLSchema");
        ns.Add("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        Envelope env = new Envelope {
            Body = new Body {
                QueryResponse = new QueryResponse {
                     Faculties = new Faculties { Name = "John"}
                }
            }
        };
        ser.Serialize(Console.Out, env, ns);
    }
}

输出(@encoding 是因为Console.Out):

<?xml version="1.0" encoding="ibm850"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <QueryResponse xmlns="http://schemas.mycorp.com/test">
      <Faculties>
        <Name>John</Name>
      </Faculties>
    </QueryResponse>
  </soapenv:Body>
</soapenv:Envelope>

【讨论】:

  • 嗨,Marc,我同意 XML 语法,它们是相同的。但是由于我遗留程序的限制,我必须将 Envelope 放入命名空间 soapenv。任何想法如何解决这个问题?
  • 谢谢 Marc,我已经尝试过您的解决方案,只剩下一个小问题,即我想从元素 QueryResponse 定义默认命名空间 xmlns="schemas.mycorp.com/test,而不是从顶部关卡元素信封,有什么解决办法吗?
  • 只需将 [XmlElement(Namespace="schemas.mycorp.com/test")] 添加到您希望位于不同(默认)命名空间中的属性上。
  • @George2:您应该针对遗留系统提交错误报告,提醒他们应该支持 XML。他们目前支持的内容类似于 XML,但不支持基本标准。
  • 我们已经说过...使用 XmlSerializerNamespaces 并标记属性...我可以尝试做一个示例,但是...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多