序列化 xml:2 个列表混淆
Serialization xml : 2 lists mixed up
我目前 运行 在 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),并且级别 > 1 的对象通过 Guid 附加到父节点。
我希望它保存在这样的 xml 结构中(非常简单,但你明白了):
<Article>
<Elt>Element 0</Elt>
<Block name='Block 1'>
<Elt>Element 1</Elt>
</Block>
<Elt>Element 2</Elt>
</Article>
我用来序列化的 C# 中的 class 如下所示:
[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 classes。 XBlock class 有一个 innerBlocks 属性,它只是一个允许多个级别的列表。
我的问题在于,当我尝试创建我的 XArticle 时,Blocks 和 Elts 存储在 2 个单独的列表中,所以当然,当我尝试序列化它时,它会依次序列化一个列表,我完全如果它们混合在一起,则会丢失块和 elt 的顺序。
这是我得到的 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-classes.
的函数,请告诉我
如果你想在序列化列表中混合类型,你应该创建一个 属性 具有 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 { }
}
这将创建一个按文本 属性 排序的列表。
您可以替换为您希望作为排序依据的任何其他字段。
非常感谢您的帮助,多亏了我才得以解决我的问题!
对于可能对其他人有帮助的人,我设法通过创建 2 个递归函数来重新排序我的最终 xml :
首先,反序列化后将List<object> Elements
转换为2个列表(List<XBlock> Blocks
和List<XElt> Elts
,记住,它们在程序中无处不在必须喂食)。
第二次,在序列化之前将 2 个列表(Blocks 和 Elts)合并为一个列表(Elements)。
我目前 运行 在 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),并且级别 > 1 的对象通过 Guid 附加到父节点。
我希望它保存在这样的 xml 结构中(非常简单,但你明白了):
<Article>
<Elt>Element 0</Elt>
<Block name='Block 1'>
<Elt>Element 1</Elt>
</Block>
<Elt>Element 2</Elt>
</Article>
我用来序列化的 C# 中的 class 如下所示:
[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 classes。 XBlock class 有一个 innerBlocks 属性,它只是一个允许多个级别的列表。
我的问题在于,当我尝试创建我的 XArticle 时,Blocks 和 Elts 存储在 2 个单独的列表中,所以当然,当我尝试序列化它时,它会依次序列化一个列表,我完全如果它们混合在一起,则会丢失块和 elt 的顺序。
这是我得到的 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-classes.
的函数,请告诉我如果你想在序列化列表中混合类型,你应该创建一个 属性 具有 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 { }
}
这将创建一个按文本 属性 排序的列表。 您可以替换为您希望作为排序依据的任何其他字段。
非常感谢您的帮助,多亏了我才得以解决我的问题!
对于可能对其他人有帮助的人,我设法通过创建 2 个递归函数来重新排序我的最终 xml :
首先,反序列化后将
List<object> Elements
转换为2个列表(List<XBlock> Blocks
和List<XElt> Elts
,记住,它们在程序中无处不在必须喂食)。第二次,在序列化之前将 2 个列表(Blocks 和 Elts)合并为一个列表(Elements)。