C# XmlSerializer xmlns in child element matching parent

2.7k Views Asked by At

I'm using XmlSerializer to create a xml doc in use for ebay's large merchant services.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BulkDataExchangeRequests xmlns="urn:ebay:apis:eBLBaseComponents">
    <Header>
        <SiteID>0</SiteID>
        <Version>775</Version>
    </Header>
    <AddFixedPriceItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<Version>775</Version>

<Item>
    <AutoPay>false</AutoPay>
    <BuyerProtection>ItemIneligible</BuyerProtection>
    <BuyItNowPrice currencyID="USD">0.0</BuyItNowPrice>
    <Country>US</Country>
    <Currency>USD</Currency>
    <Description>test</Description>
    <GiftIcon>0</GiftIcon>
</Item>
</AddFixedPriceItemRequest>
</BulkDataExchangeRequests>

The problem I'm having is getting the AddFixedPriceItemRequest generated by the serializer to actually contain that xmlns like the BulkDataExchangeRequests element has. It seems to be a requirement in order for this to work. I generate the bulk tag using:

writer.WriteStartElement("BulkDataExchangeRequests", "urn:ebay:apis:eBLBaseComponents");

I create a serializer.

serializer = new XmlSerializer(typeof(AddFixedPriceItemRequestType));//, "urn:ebay:apis:eBLBaseComponents");

and serialize with the namespace

request = new AddFixedPriceItemRequestType()
{
//populate data.
};

XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "urn:ebay:apis:eBLBaseComponents");

serializer.Serialize(writer, request, namespaces);

This is the type with the xml attributes:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.5420")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents",TypeName="AddFixedPriceItemRequest")]
public partial class AddFixedPriceItemRequestType : AbstractRequestType {
//filled in class
}

my output ends up like this:

<AddFixedPriceItemRequest xmlns="">
   <ErrorLanguage xmlns="urn:ebay:apis:eBLBaseComponents">en_US</ErrorLanguage>
    <Version xmlns="urn:ebay:apis:eBLBaseComponents">837</Version>
    <Item p4:type="Item" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:ebay:apis:eBLBaseComponents">

Could someone help out with how to get xmlns of addfixedpriceitemrequest set to match the bulk xmlns via the serializer. Or recommend another way to do it. I was trying to avoid writing each property out with createelement/writeelement.

3

There are 3 best solutions below

0
Aleksei Poliakov On

The problem most likely lies in the XmlTypeAttribute - it seems you use your class as the top level container - you should use XmlRootAttribute insted. This way you will get urn:ebay:apis:eBLBaseComponents placed in correct location.

Sample:

void Main()
{
    var t = new A {FieldOfB = new B {C = 5}};

    var serializer = new XmlSerializer(typeof(A));


    using (var writer = new StringWriter())
    {
        serializer.Serialize(writer, t);
        writer.ToString().Dump();
    }
}

When used with this class definitions:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")]
public class A
{
    public B FieldOfB {get;set;}
}

public class B
{
    public int C {get;set;}
}

yields this result:

<?xml version="1.0" encoding="utf-16"?>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <FieldOfB xmlns="urn:ebay:apis:eBLBaseComponents">
    <C>5</C>
  </FieldOfB>
</A>

And if you fix the attribute:

[System.Xml.Serialization.XmlRootAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")]
public class A
{
    public B FieldOfB {get;set;}
}

public class B
{
    public int C {get;set;}
}

You get this:

<?xml version="1.0" encoding="utf-16"?>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:ebay:apis:eBLBaseComponents">
  <FieldOfB>
    <C>5</C>
  </FieldOfB>
</A>
0
Valentin Todorov On

That works for me


 ItemType itemType = new ItemType()
 {
     //populate data.
 };
 ApiCall apiCall = new AddItemCall() { Item = itemType };
 AddItemRequestType addFixedPriceItemRequestType = ((AddItemCall)apiCall).ApiRequest;
 XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
     new XmlQualifiedName(string.Empty, "urn:ebay:apis:eBLBaseComponents")});
 XmlSerializer xmlSerializer = new XmlSerializer(
     addFixedPriceItemRequestType.GetType(), "urn:ebay:apis:eBLBaseComponents");
 MemoryStream memoryStream = new MemoryStream();
 xmlSerializer.Serialize(memoryStream, addFixedPriceItemRequestType , namespaces);
 memoryStream.Seek((long)0, SeekOrigin.Begin);
 XmlDocument xmlDocument = new XmlDocument();
 xmlDocument.Load(memoryStream);
 memoryStream.Close();
 string addItemRequestTypeXML = xmlDocument.OuterXml;

The output is going to be:


 <AddItemRequestType xmlns="urn:ebay:apis:eBLBaseComponents">
  <Item>
    <ApplicationData></ApplicationData>
    <AutoPay>false</AutoPay>
    <CategoryMappingAllowed>true</CategoryMappingAllowed>
    <Country>US</Country>
    <Currency>EUR</Currency>
    <Description>
    ....

 <AddItemRequestType>
0
Jeffrey Xuan On

eBay requires namespace setting in Trade API only. One solution is to remove namespace setting in BulkDataExchange objects, and add namespace setting in Trade API object only. This is not a standard XML format, however eBay only accept this.

In your case, this might do the trick to eBay:

writer.WriteStartElement("BulkDataExchangeRequests", "");