views:

30

answers:

2

I'm trying to create an XML output file to import into another program. The example XML file I was given looks like this:

    <SalesOrder>
  <OrderHeader>
    <BillTo>
      <EntityID>1234</EntityID>
    </BillTo>
  </OrderHeader>
  <LineItemList>
    <OrderLineComment>
      <LineItemID>1</LineItemID>
    </OrderLineComment>
    <LineItem>
      ...
    </LineItem>
    <LineItem>
      ...
    </LineItem>
    <LineItem>
      ...
    </LineItem>
    ...
  </LineItemList>
</SalesOrder>

I have a C# project that is able to output this type of file using an XmlSerializer with the exception of this part:

  <LineItemList>
    <OrderLineComment>
      <LineItemID>1</LineItemID>
    </OrderLineComment>

The LineItemList section is simply a list of LineItems, but at the beginning of the LineItemList there is tacked this different element OrderLineComment.

If I represent this as an array of LineItems, then it looks the same except it's missing the OrderLineComment. If I represent this as a new object LineItemList containing an OrderLineComment and an array of LineItems, I get this:

  <LineItemList>
    <OrderLineComment>
      <LineItemID>1</LineItemID>
    </OrderLineComment>
    <LineItems>
      <LineItem>
    ...
      </LineItem>
      ...
    </LineItems>

Which has what I want, except it wraps all the LineItems with the <LineItems> tag, which isn't what I want either.

So what I'm wondering is:

  1. Is there a way to do this via XmlSerializer? If so, how?
  2. If there isn't, and I have to rewrite the code to use something other than XmlSerializer, what would be the best way to do this and why?

Thanks in advance.

+1  A: 

You can always implement IXmlSerializable interface on your type. It allows serialization of any complexity and it works with XmlSerializer.

Edit:

Here is the example of generated code if you want to achieve it with standard attributes. I created xsd from your xml and generated the code with XSD.exe.

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class SalesOrder {

    private OrderHeader orderHeaderField;

    private LineItemList lineItemListField;

    /// <remarks/>
    public OrderHeader OrderHeader {
        get {
            return this.orderHeaderField;
        }
        set {
            this.orderHeaderField = value;
        }
    }

    /// <remarks/>
    public LineItemList LineItemList {
        get {
            return this.lineItemListField;
        }
        set {
            this.lineItemListField = value;
        }
    }
}

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

    private BillTo billToField;

    /// <remarks/>
    public BillTo BillTo {
        get {
            return this.billToField;
        }
        set {
            this.billToField = value;
        }
    }
}

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

    private short entityIDField;

    /// <remarks/>
    public short EntityID {
        get {
            return this.entityIDField;
        }
        set {
            this.entityIDField = value;
        }
    }
}

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

    private OrderLineComment orderLineCommentField;

    private string[] lineItemField;

    /// <remarks/>
    public OrderLineComment OrderLineComment {
        get {
            return this.orderLineCommentField;
        }
        set {
            this.orderLineCommentField = value;
        }
    }

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

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

    private sbyte lineItemIDField;

    /// <remarks/>
    public sbyte LineItemID {
        get {
            return this.lineItemIDField;
        }
        set {
            this.lineItemIDField = value;
        }
    }
}
Ladislav Mrnka
upvoted because after starting to try this it was evident that it will achieve the result I'm looking for, it's just that the base class solution is a bit quicker and easier. Thank you very much for your answer though.
Jordan
+2  A: 

You can make a OrderLineComment and LineItem derive from a common base class :

public abstract class LineItemBase
{
    ...
}

public class LineItem : LineItemBase
{
    ...
}

public class OrderLineComment : LineItemBase
{
    ...
}

Then declare the LineItemList property as a collection of LineItemBase objects, and use the XmlArrayItem attribute to specify which types can be included in the collection:

[XmlArrayItem(typeof(LineItem))]
[XmlArrayItem(typeof(OrderLineComment))]
public List<LineItemBase> LineItemList { get; set; }

This should achieve what you want

Thomas Levesque
worked like a charm - thanks.
Jordan