2012-03-15 13 views
1

私はc#とXmlSerialiserクラスを使用してDTOオブジェクトからxmlを作成しています。異なる子ノードを持つノードをDTOオブジェクトからシリアル化する

今私は、このようなXMLテキストを生成する必要があります。

<Order> 
    <OrderNo>123456</OrderNo> 
    <Positions> 
     <TextPosition> 
      <Text>This is Order No 123456</Text> 
     </TextPosition> 
     <ItemPosition> 
      <ItemId>14789</ItemId> 
      <ItemName>Product 1</ItemName> 
     </ItemPosition> 
     </TextPosition> 
     <ItemPosition> 
      <ItemId>456</ItemId> 
      <ItemName>Product 2</ItemName> 
     </ItemPosition> 
     <TextPosition> 
      <Text>Good bye</Text> 
     </TextPosition> 
     <SumPosition> 
      <Value>123.45 USD</Value> 
     </SumPosition> 
    </Positions> 
</Order> 

は、私は私のクラスを飾るために属性を使用して、すべてが正常に動作します。 まだ解決できなかったことが1つあります。別のタグTextPosition, ItemPosition, ValuePosition, ...が入ったタグPositionsを生成する必要があります。

これをC#でどのように実現できますか?

現在、私のクラスの注文が

[XmlElement("Positions")] 
public PositionList Positions { get; set; } 

が含まれていPositionListは、私は私のOrderクラスに

[XmlInclude(typeof(Textposition))] 
[XmlInclude(typeof(ItemPosition))] 
[XmlInclude(typeof(SumPosition))] 

を追加InvalidOperationExceptionがを避けるために

public class PositionList 
{ 
    [XmlElement("Positions")] 
    public List<Object> Positions { get; set; } 
} 

を持つクラスです。

しかし、シリアライザが生成代わり

<Positions> 
    <TextPosition>...</TextPosition> 
</Positions> 

を生成する:

<Position d4p1:type="TextPosition" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">...</Position> 

事があり、中にはそれを私の自己をデシリアライズが、非常にXMLファイルを提供する必要はありません1人の顧客の厳格なフォーマット。これを実現する方法はありますか?

答えて

2

方法があります:XMLファイルにそれをシリアライズ

public class Order 
{ 
    public List<BasePosition> Positions { get; set; } 
    public Order() { Positions = new List<BasePosition>(); } 
} 

public class BasePosition 
{ 

} 

public class TextPosition : BasePosition 
{ 
    public string Text { get; set; } 
} 

public class ItemPosition : BasePosition 
{ 
    public int ItemId { get; set; } 
    public string ItemName { get; set; } 
} 

public class SumPosition : BasePosition 
{ 
    public string Value { get; set; } 
} 

例:

Order o = new Order(); 
o.Positions.Add(new TextPosition() { Text = "This is Order No 123456" }); 
o.Positions.Add(new ItemPosition() { ItemId = 14789, ItemName = "Product 1" }); 
o.Positions.Add(new TextPosition()); 
o.Positions.Add(new ItemPosition() { ItemId = 456, ItemName = "Product 2" }); 
o.Positions.Add(new SumPosition() { Value = "123.45 USB" }); 
XmlAttributeOverrides specific_attributes = new XmlAttributeOverrides(); 
XmlAttributes attrs = new XmlAttributes(); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(TextPosition))); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(ItemPosition))); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(SumPosition))); 
specific_attributes.Add(typeof(Order), "Positions", attrs); 
XmlSerializer ser = new XmlSerializer(typeof(Order), specific_attributes); 

using(MemoryStream mem_stream = new MemoryStream()) 
{ 
    ser.Serialize(mem_stream, o); 
    using (BinaryWriter bw = new BinaryWriter(new FileStream("orders.xml", FileMode.Create))) 
    { 
     bw.Write(mem_stream.ToArray()); 
    } 
} 

結果:

<?xml version="1.0"?> 
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <TextPosition> 
    <Text>This is Order No 123456</Text> 
    </TextPosition> 
    <ItemPosition> 
    <ItemId>14789</ItemId> 
    <ItemName>Product 1</ItemName> 
    </ItemPosition> 
    <TextPosition /> 
    <ItemPosition> 
    <ItemId>456</ItemId> 
    <ItemName>Product 2</ItemName> 
    </ItemPosition> 
    <SumPosition> 
    <Value>123.45 USB</Value> 
    </SumPosition> 
</Order> 
+1

恐ろしい!私は、1つのプロパティ 'public list Positions {get; set;}'でヘルパークラスPositionListを追加して、注文と位置の間に余分な ''タグを付けました。どうもありがとうございました。 –

+0

問題はありません、私が助けることができてうれしい、余分なタグを忘れて申し訳ありません:) – SwDevMan81

1

非常に厳密な形式のXMLが必要な場合は、シリアライザを使用するのが最適ではないかもしれません。シリアライザを使用すると、利便性のために制御権を放棄し、今はその制御権を取り戻すために戦っています。

XDocumentクラスであるLinq to XMLの使用を検討してください。

var doc = 
    new XElement("Order", 
     new XElement ("OrderNo", 123456), 
     new XElement ("Positions", 
     myPositions.Select(p => new XElement("Position", ....))); 
+0

「あなたは利便性のための制御をあきらめ、そして今、あなたはそのコントロールを取り戻すために戦っている」それは非常によく述べられています。 –

+0

'あなたは利便性のためにコントロールをあきらめ、今はコントロールを取り戻すために戦っています。私はこれに同意しません。 AttributesとXmlSerializerを使ったAOPのアプローチは非常に強力で、 'XmlAttributeOverrides'を使って私は必要な結果を得ることができます。 DTOクラスはシリアライザよりも別のDLLに存在するので、ロジック自体を変更することなく、将来的にアップデートを適用することができます。とにかくXDocumentアプローチの+1は有望です(おそらく私は将来別のタスクに使うことを検討します)。 –

関連する問題