gpt4 book ai didi

c# - 使用父对象引用的 XML 反序列化

转载 作者:太空宇宙 更新时间:2023-11-03 13:03:55 25 4
gpt4 key购买 nike

我有一个描述网站的 XML 文件。它由Site作为根节点组成,可以有Pages,Pages可以有Button或TextBox和Dialogs等Object。对话框也可以有对象。

在对应的C#类中,都是从Element派生的。当我反序列化 XML 时,我如何才能引用正在构建的元素的父级?

我被告知复杂类型不能以这种方式反序列化,但如果我向 XML 中的每个元素添加一个 ID 字段,则可以使用该字段引用父元素,从而正确反序列化。我将如何实现?我不想为 XML 文件中的每个元素手动添加 ID 字段...

我的元素类:

public class Element 
{
public string Name { get; set; }
public string TagName { get; set; }
public string XPath { get; set; }

[XmlElement(ElementName = "Site", Type = typeof(Site))]
[XmlElement(ElementName = "Page", Type = typeof(Page))]
[XmlElement(ElementName = "Dialog", Type = typeof(Dialog))]
public Element Parent { get; set; }

[XmlArray("Children", IsNullable = false)]
[XmlArrayItem(Type = typeof(TextBox))]
[XmlArrayItem(Type = typeof(Page))]
[XmlArrayItem(Type = typeof(Button))]
[XmlArrayItem(Type = typeof(Dialog))]
public Collection<Element> Children { get; set; }

}

我的反序列化:

public Site GetSiteFromXml(string filePath, string fileName)
{
XmlSerializer serializer = new XmlSerializer(typeof(Site));
return serializer.Deserialize(new XmlTextReader(Path.Combine(filePath, fileName))) as Site;
}

我的 XML 文件:

<Site>
<Name>WebSiteName</Name>
<Url>https://site.url</Url>
<Children>
<Page>
<Name>HomePage</Name>
<Address>#page=1</Address>
<Children>
<Button>
<Name>LoginDialogButton</Name>
<Id>LoginIcon</Id>
<XPath>//*[@id="LoginIcon"]</XPath>
<Enabled>true</Enabled>
<Action>OpenLoginDialog</Action>
</Button>
<Dialog>
<Name>LoginPopUpDialog</Name>
<Id>loginModal</Id>
<Children>
<TextBox>
<Name>UserNameInput</Name>
</TextBox>
<TextBox>
<Name>PasswordInput</Name>
</TextBox>
<Button>
<Name>LoginButton</Name>
<Action>DialogDismiss</Action>
</Button>
</Children>
</Dialog>
</Children>
</Page>
</Children>
</Site>

最佳答案

由于您没有任何机制来保证 ParentChildren属性保持同步,最简单的方法是告诉 XmlSerializer忽略这两个属性,并添加一个代理属性,该属性将子项列表作为数组(而不是集合)返回。在代理属性的 setter 中,填充 Children集合并设置 Parent每个 child 的属性:

public class Element
{
public Element() { Children = new Collection<Element>(); }

public string Name { get; set; }
public string TagName { get; set; }
public string XPath { get; set; }

[XmlIgnore]
public Element Parent { get; set; }

[XmlIgnore]
public Collection<Element> Children { get; set; }

[XmlArray("Children", IsNullable = false)]
[XmlArrayItem(Type = typeof(TextBox))]
[XmlArrayItem(Type = typeof(Page))]
[XmlArrayItem(Type = typeof(Button))]
[XmlArrayItem(Type = typeof(Dialog))]
[XmlArrayItem(Type = typeof(Site))]
public Element[] ChildArrayCopy
{
get
{
return Children.ToArray();
}
set
{
Children.Clear();
if (value != null)
foreach (var child in value)
child.SetParent(this);
}
}
}

public static class ElementExtensions
{
public static void SetParent(this Element child, Element parent)
{
if (child == null)
throw new ArgumentNullException();
if (child.Parent == parent)
return; // Nothing to do.
if (child.Parent != null)
child.Parent.Children.Remove(child);
child.Parent = parent;
if (parent != null)
parent.Children.Add(child);
}
}

现在可以成功反序列化和序列化您的 XML。

顺便说一下,我会考虑更换你的 public Collection<Element> Children { get; set; }public ReadOnlyCollection<Element> Children { get; } .然后将子项保存在私有(private)列表中,并返回 list.AsReadOnly() .这样做之后,您现在可以保证子列表在 Parent 中保持最新。 setter :

public class Element
{

public Element() { }

public string Name { get; set; }
public string TagName { get; set; }
public string XPath { get; set; }

private readonly List<Element> children = new List<Element>();
private Element parent = null;

[XmlIgnore]
public Element Parent
{
get
{
return parent;
}
set
{
if (parent == value)
return;
if (parent != null)
parent.children.Remove(this);
parent = value;
if (parent != null)
parent.children.Add(this);
}
}

[XmlIgnore]
public ReadOnlyCollection<Element> Children
{
get
{
return children.AsReadOnly();
}
}

[XmlArray("Children", IsNullable = false)]
[XmlArrayItem(Type = typeof(TextBox))]
[XmlArrayItem(Type = typeof(Page))]
[XmlArrayItem(Type = typeof(Button))]
[XmlArrayItem(Type = typeof(Dialog))]
[XmlArrayItem(Type = typeof(Site))]
public Element[] ChildArrayCopy
{
get
{
return Children.ToArray();
}
set
{
if (value != null)
foreach (var child in value)
child.Parent = this;
}
}
}

关于c# - 使用父对象引用的 XML 反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31424460/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com