【问题标题】:Deserializing cXML to C# Class将 cXML 反序列化为 C# 类
【发布时间】:2016-01-05 19:50:00
【问题描述】:

我正在尝试将 cXML 字符串反序列化为 C# 类。但是,在反序列化时,除了要反序列化的根元素之外,我似乎什么也得不到。 How to Deserialize XML document 似乎提供了最大的帮助,并且使用该示例我设法反序列化根 cXML 标记,但这不适用于嵌套对象 PunchOutSetupRequest,这是我真正需要反序列化的对象。

在向您展示代码墙之前,我的问题是,如何在不更改 cXML.cs 文件的情况下将这些对象正确反序列化为下面定义的 cXML 类?由于这是一个标准,除非绝对必须,否则我不想编辑它。我的代码是公平的游戏。提前感谢您提供的任何帮助,因为我知道这个主题在 SO 中涉及的范围很广。

我有这个用于 cXML 的 XSD 文件,我使用 xsd.exe 工具将其转换为 C# 类。我不会在此处粘贴整个架构以避免稀释问题,但如果您需要更完整的图片,可以转到cxml.org

我的 cXML 代码,它只是反序列化属性并且不包含 cXML 中定义的 Header 或 Request 对象:

using (TextReader reader = new StringReader(text))
            {
                try
                {
                    XmlRootAttribute xRoot = new XmlRootAttribute();
                    xRoot.ElementName = "cXML";
                    xRoot.IsNullable = true;
                    var serializer = new XmlSerializer(typeof(cXML), xRoot);
                    cxml = (cXML)serializer.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    string r = "";
                }
            }

我的 PunchOutSetupRequest 反序列化代码。 尽管我将 xRoot 元素设置为 PunchOutSetupRequest,但当它将 cXML 视为根节点时,此代码会引发错误。

using (TextReader reader = new StringReader(text))
            {
                try
                {
                    XmlRootAttribute xRoot = new XmlRootAttribute();
                    xRoot.ElementName = "PunchOutSetupRequest";
                    xRoot.IsNullable = true;
                    var serializer = new XmlSerializer(typeof(PunchOutSetupRequest), xRoot);
                    PunchOutSetupRequest request;
                    request = (PunchOutSetupRequest)serializer.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    string r = "";
                }
            }

文本变量值(数据已编辑):

<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.1.007/cXML.dtd">
<cXML version="1.1.007" xml:lang="en-US" payloadID="" timestamp="2016-01-    04T03:21:32-05:00">
   <Header>
      <From>
         <Credential domain="">
            <Identity></Identity>
         </Credential>
      </From>
      <To>
         <Credential domain="">
            <Identity></Identity>
         </Credential>
      </To>
      <Sender>
         <Credential domain="">
            <Identity></Identity>
            <SharedSecret></SharedSecret>
         </Credential>
         <UserAgent></UserAgent>
      </Sender>
   </Header>
   <Request>
      <PunchOutSetupRequest operation="create">
         <BuyerCookie></BuyerCookie>
         <Extrinsic name="User"></Extrinsic>
         <BrowserFormPost>
            <URL></URL>
         </BrowserFormPost>
         <Contact>
            <Name xml:lang="en-US"></Name>
            <Email></Email>
         </Contact>
         <SupplierSetup>
            <URL></URL>
         </SupplierSetup>
      </PunchOutSetupRequest>
   </Request>
</cXML>

cXML 类由xsd.exe 生成(分段)

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/cXML")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/cXML", IsNullable = false)]
public partial class cXML
{

private object[] itemsField;

private string versionField;

private string payloadIDField;

private string timestampField;

private string langField;

public cXML()
{
    this.versionField = "1.1.010";
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Header", typeof(Header))]
[System.Xml.Serialization.XmlElementAttribute("Message", typeof(Message))]
[System.Xml.Serialization.XmlElementAttribute("Request", typeof(Request))]
[System.Xml.Serialization.XmlElementAttribute("Response", typeof(Response))]
public object[] Items
{
    get
    {
        return this.itemsField;
    }
    set
    {
        this.itemsField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute("1.1.010")]
public string version
{
    get
    {
        return this.versionField;
    }
    set
    {
        this.versionField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string payloadID
{
    get
    {
        return this.payloadIDField;
    }
    set
    {
        this.payloadIDField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string timestamp
{
    get
    {
        return this.timestampField;
    }
    set
    {
        this.timestampField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified, Namespace = "http://www.w3.org/XML/1998/namespace")]
public string lang
{
    get
    {
        return this.langField;
    }
    set
    {
        this.langField = value;
    }
}
}    

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/cXML")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/cXML", IsNullable = false)]
public partial class PunchOutSetupRequest
{

private BuyerCookie buyerCookieField;

private Extrinsic[] extrinsicField;

private BrowserFormPost browserFormPostField;

private Contact[] contactField;

private SupplierSetup supplierSetupField;

private ShipTo shipToField;

private SelectedItem selectedItemField;

private ItemOut[] itemOutField;

private PunchOutSetupRequestOperation operationField;

/// <remarks/>
public BuyerCookie BuyerCookie
{
    get
    {
        return this.buyerCookieField;
    }
    set
    {
        this.buyerCookieField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Extrinsic")]
public Extrinsic[] Extrinsic
{
    get
    {
        return this.extrinsicField;
    }
    set
    {
        this.extrinsicField = value;
    }
}

/// <remarks/>
public BrowserFormPost BrowserFormPost
{
    get
    {
        return this.browserFormPostField;
    }
    set
    {
        this.browserFormPostField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Contact")]
public Contact[] Contact
{
    get
    {
        return this.contactField;
    }
    set
    {
        this.contactField = value;
    }
}

/// <remarks/>
public SupplierSetup SupplierSetup
{
    get
    {
        return this.supplierSetupField;
    }
    set
    {
        this.supplierSetupField = value;
    }
}

/// <remarks/>
public ShipTo ShipTo
{
    get
    {
        return this.shipToField;
    }
    set
    {
        this.shipToField = value;
    }
}

/// <remarks/>
public SelectedItem SelectedItem
{
    get
    {
        return this.selectedItemField;
    }
    set
    {
        this.selectedItemField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("ItemOut")]
public ItemOut[] ItemOut
{
    get
    {
        return this.itemOutField;
    }
    set
    {
        this.itemOutField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public PunchOutSetupRequestOperation operation
{
    get
    {
        return this.operationField;
    }
    set
    {
        this.operationField = value;
    }
}
}

【问题讨论】:

  • 6周过去了,你还需要答案吗,还是已经解决了?
  • 我确实做到了。我确实通过编辑 cXML 文件采取了不同的方法。我相信 xsd.exe 工具生成的 C# 类不正确。我收到的 cXML 似乎与类的结构不匹配。了解 xsd.exe 工具提供的内容似乎可以正常工作,尽管它的过程更长。
  • 检查您从市场(或其他)获得的 CXML 版本。您在上面发布的版本 - 非常 - 旧。大多数已经升级到 1.2.025 或接近 1.2.025(我在美国签订了几个合同),当试图从 XSD 可以处理的 DTD 生成模式时,更高版本会阻塞 VS。我不得不使用 xmlPad(我认为?),并且我使用了 XsdObjGen.exe 而不是 XSD.exe。我目前正在使用 Xsd2Code 以从该工具中获得更好的结果,无论是一般情况下还是特别是使用 CXML。

标签: c# xml deserialization cxml cxml-commercexml


【解决方案1】:

TL;DR; 我通过在将 xsd 文件转换为 c# 模型之前对其进行编辑来解决此问题。

在从 DTD 生成的 XSD 中,更改:

&lt;xs:schema xmlns="http://tempuri.org/cXML" xmlns:ds="uri:ds" elementFormDefault="qualified" targetNamespace="http://tempuri.org/cXML" xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;

收件人:

&lt;xs:schema xmlns:ds="uri:ds" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;

更长的解释:

如果在 DTD 文件上使用 Visual Studio 的 [XML]->[Create Schema],Visual Studio 将生成一个目标命名空间为http://tempuri.org/cXML 的 XSD。

如果您从该 XSD 生成 C# 模型而不删除这些命名空间引用(使用 xsd2code 或 Visual Studio 的 xsd blah.xsd /classes),则 XmlSerializer 将期望该命名空间用于您要反序列化的 XML。

SAP Ariba 等平台不使用该 tempuri.org 命名空间。因此将跳过 XML 节点,因为没有名称空间引用,节点将无法识别。我发现这是因为 XmlSerializer.UnknownNode 事件触发了,告诉我它无法识别 Header 和 Request 等节点,并且它需要具有 tempuri.org 命名空间前缀的节点。

因此,如果您首先从 XSD 中删除虚假命名空间,然后生成类(我为此使用了 xsd2code),那么您最终会得到有效的 c# (de)serializable 模型。

你也不需要使用xRoot.ElementName = "cXML";。它将从 c# 类中获取根节点,因为它不寻找带有 tempuri.org 命名空间的 &lt;cXML&gt; 标记。

因此,这样您就不需要“消化”从 XSD 生成的类,并且可以按原样使用它们。

【讨论】:

    猜你喜欢
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多