序列化xml:2列表混合

时间:2015-04-10 08:22:15

标签: c# xml serialization xpath

我目前遇到了C#中xml序列化的问题。

我的程序中有一个像这样的XML结构代表树:

<FlatNodeTree>
  <Node>
    <Level>1</Level>
    <Name>Element 0</Name>
    <Guid>AAA</Guid>
    <NodeType>XElt</NodeType>
    <GuidParent />
  </Node>
  <Node>
    <Level>1</Level>
    <Name>Block 1</Name>
    <Guid>BBB</Guid>
    <NodeType>XBlock</NodeType>
    <GuidParent />
  </Node>
  <Node>
    <Level>2</Level>
    <Name>Element 1</Name>
    <Guid>CCC</Guid>
    <NodeType>XElt</NodeType>
    <GuidParent>BBB</GuidParent>
  </Node>
  <Node>
    <Level>1</Level>
    <Name>Element 2</Name>
    <Guid>DDD</Guid>
    <NodeType>XElt</NodeType>
    <GuidParent />
  </Node>
</FlatNodeTree>

你可以看到有节点(XBlock)和叶子(XElt),以及水平对象&gt; 1由Guid附加到父节点。

我希望将它保存在这样的xml结构中(它非常简单,但你明白了):

<Article>
    <Elt>Element 0</Elt>
    <Block name='Block 1'>
        <Elt>Element 1</Elt>
    </Block>
    <Elt>Element 2</Elt>
</Article>

我在C#中用来序列化的类看起来像这样:

 [Serializable]
 public class XArticle
 {
     public XArticle()
     {
         Blocks = new List<XBlock>();
         Elts = new List<XElt>();
     }

     [XmlElement("block")]
     public List<XBlock> Blocks { get; set; }

     [XmlElement("elt")]
     public List<XElt> Elts { get; set; }

      /*Plenty of other stuff*/

 }

我也有XBlock和XElt类。 XBlock类有一个innerBlocks属性,它只是一个允许多个级别的List。

我的问题在于,当我尝试创建我的XArticle时,Blocks和Elts存储在2个单独的列表中,因此当我尝试序列化它时,它会逐个序列化列表并且我完全失去了块和elts的顺序如果它们是混合的。

以下是我获取的XML的示例,而不是之前发布的XML:

 <Article>
    <Block name='Block 1'>
        <Elt>Element 1</Elt>
    </Block>
    <Elt>Element 0</Elt>
    <Elt>Element 2</Elt>
</Article>

您可以看到它首先序列化所有块,然后序列化每个节点内的所有元素。

我对序列化知之甚少,我想知道是否有xml指令或可以解决此问题的东西。

我想到的解决方案是在创建无组织的xml后重新排序Blocks和Elts标签,但也许有更好的解决方案。

PS:我使用System.Xml.Serialization.XmlSerializer

PPS:告诉我你是否需要看到将xpath数据转换为X-class的函数。

2 个答案:

答案 0 :(得分:0)

如果要混合序列化列表中的类型,则应创建一个具有2个装饰属性的属性,如下所示:

[Serializable]
public class XArticle
{

    [XmlElement(Type = typeof(XBlock), ElementName = "Block")]
    [XmlElement(Type = typeof(XElt), ElementName = "Elt")]
    public List<object> Elements { get; set; }

}

如果您使用以下内容填充元素:

Elements = new List<object> { new XElt { Text = "Element 0" }, new XBlock { Elt = new XElt { Text = "Element 1 " }, Name = "Block 1" }, new XElt { Text = "Element 2 " } };

它产生xml:

<?xml version="1.0"?>
<XArticle xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Elt>Element 0</Elt>
  <Block name="Block 1">
    <Elt>Element 1 </Elt>
  </Block>
  <Elt>Element 2 </Elt>
</XArticle>

编辑: 如果必须保留Blocks和Elts属性,则可以执行以下操作:

[Serializable]
public class XArticle
{
    [XmlIgnore]
    public List<XBlock> Blocks { get; set; }


    [XmlIgnore]
    public List<XElt> Elts { get; set; }

    [XmlElement(Type = typeof(XBlock), ElementName = "Block")]
    [XmlElement(Type = typeof(XElt), ElementName = "Elt")]
    public List<object> Elements
    {
        get
        {
            return Blocks.Select(b => new KeyValuePair<string, object>(b.Elt.Text, b))
                .Concat(Elts.Select(e => new KeyValuePair<string, object>(e.Text, e)))
                .OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToList();
        }
        set { }
    }

这将创建一个按Text属性排序的列表。 您可以替换您希望订购的任何其他字段。

答案 1 :(得分:0)

非常感谢你的帮助,我能够解决我的问题!

对于其他人来说,它可能有所帮助,我设法通过创建2个递归函数重新排序我的最终xml:

  • 第一个,在反序列化之后转换2个列表中的List<object> ElementsList<XBlock> BlocksList<XElt> Elts,请记住,它们在程序中被使用并且必须被馈送)。

  • 第二个,在序列化之前将2个列表(Blocks和Elts)合并为一个列表(Elements)。