Десериализация cXML в класс C#

Я пытаюсь десериализовать строку cXML в классы C#. Однако при десериализации я не могу получить ничего, кроме корневого элемента, для десериализации. Как десериализовать XML-документ, по- видимому, больше всего помогает, и на этом примере мне удалось десериализовать корневой тег cXML, но это не работает на вложенном объекте. PunchOutSetupRequest который является объектом, который мне действительно нужен для десериализации.

Мой вопрос, прежде чем показать вам стену кода, заключается в том, как правильно десериализовать эти объекты в классы cXML, определенные ниже, без изменения cXML.cs файл? Поскольку это стандарт, я бы предпочел не редактировать его, если только мне это не нужно. Мой код - честная игра. Заранее благодарю за любую помощь, так как я знаю, что эта тема широко освещена в SO.

У меня есть этот XSD-файл для cXML, который я использовал xsd.exe инструмент для преобразования в C# классы. Я не буду вставлять сюда всю схему, чтобы не разбавлять вопрос, но вы можете перейти на cxml.org, если вам нужна более полная картина.

Мой код для cXML, который просто десериализует атрибуты и не содержит объектов Header или Request, определенных в cXML:

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 десериализации. Это выдает ошибку, когда он видит cXML в качестве корневого узла, несмотря на то, что я установил xRoot элемент к PunchOutSetupRequest,

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;
    }
}
}

0 ответов

TL;DR; Я решил это, отредактировав файл xsd перед преобразованием его в модели C#.

В XSD, созданном из DTD, измените:

<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">

Кому:

<xs:schema xmlns:ds="uri:ds" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">

Более длинное объяснение:

Если вы используете Visual Studio [XML]->[Create Schema] в файле DTD, Visual Studio сгенерирует XSD с целевым пространством имен http://tempuri.org/cXML.

Если вы создаете модели C# из этого XSD, не удаляя эти ссылки на пространства имен (используя xsd2code или Visual Studio xsd blah.xsd /classes), то XmlSerializer будет ожидать, что это пространство имен будет использоваться в XML, который вы хотите десериализовать.

Такие платформы, как SAP Ariba, не используют это пространство имен tempuri.org. Таким образом, узлы XML будут пропущены, поскольку без ссылки на пространство имен узлы не распознаются. Я обнаружил это, потому что сработало событие XmlSerializer.UnknownNode, сообщившее мне, что оно не распознает такие узлы, как Header и Request, и ожидает узлов с префиксом пространства имен tempuri.org.

Поэтому, если вы сначала удалите фиктивное пространство имен из XSD, а затем сгенерируете классы (для этого я использовал xsd2code), то вы получите действительные (де) сериализуемые модели С #.

Тогда вам также не нужно использовать xRoot.ElementName = "cXML";. Он заберет корневой узел из классов C#, потому что он не ищет<cXML> с пространством имен tempuri.org.

Таким образом, вам не нужно "потрошить" классы, созданные из XSD, и вы можете использовать их как есть.

Другие вопросы по тегам