使用 XML 片段自定义应用程序 – 第二部分





3.00/5 (2投票s)
2007 年 6 月 19 日
3分钟阅读

22506

129
关于使用 XML 片段自定义应用程序的高级讨论。
在我的第一篇文章中,我描述了为什么您应该考虑使用我的库。在第二部分中,我将讨论更高级的主题。
递归结构
首先,我将检查树结构管理。每个节点将具有名称,字体颜色和图标。
public class TreeItemCollection : ElementList<TreeItem>
{
}
public class TreeItem : OwnedElement<TreeItemCollection>
{
private const string ParentName = "parent";
private TreeItem _parent;
[Serialization(ParentName)]
public TreeItem Parent
{
get { return _parent; }
set
{
if (_parent != value)
{
LogChange(ParentName, _parent, value);
_parent = value;
}
}
}
private const string ColorName = "color";
private Color _color;
[Serialization(ColorName)]
public Color Color
{
get { return _color; }
set
{
if (_color != value)
{
LogChange(ColorName, _color, value);
_color = value;
}
}
}
private const string IconName = "icon";
private string _icon;
[Serialization(IconName, SerializationSettings.SerializeAsAttribute)]
public string Icon
{
get { return _icon; }
set
{
if (_icon != value)
{
LogChange(IconName, _icon, value);
_icon = value;
}
}
}
}
您可以在TreeItem
类中看到有一个名为Parent
的属性,它表示父节点。 使用此库,处理递归结构非常简单。 看一下下面的列表
TreeItemCollection collection = new TreeItemCollection();
TreeItem root = collection.Add("root");
root.Color = Color.Red;
root.Icon = "icon1";
TreeItem item1 = collection.Add("item1");
item1.Color = Color.Black;
item1.Icon = "icon2";
TreeItem item2 = collection.Add("item2");
item2.Color = Color.White;
item2.Icon = "icon1";
TreeItem item11 = collection.Add("item11");
item11.Color = Color.Purple;
item11.Parent = item11;
item11.Icon = "icon3";
Writer.Write(collection, "test.xml", false);
collection.AcceptChanges();
item11.Parent = root;
Writer.Write(collection, "changes.xml", true);
TreeItemCollection collection2 = new TreeItemCollection();
Reader.Read("test.xml", collection2, null);
Reader.Read("changes.xml", collection2, null);
TreeItem rItem = collection2.FindElem(root.ID.Value);
TreeItem new_item11 = collection2.Find(item11.Name);
if (new_item11.Parent == rItem)
Console.WriteLine("Perfect");
如您所见,使用引用的对象非常容易。 写入和读取不需要任何额外的处理。 生成test.xml 会得到
<e:TreeItemCollection xmlns:e="elements">
<e:TreeItem color="-65536" icon="icon1"
ID="e457617f-03fd-4948-9f83-304222f3ab0b" Name="root" />
<e:TreeItem color="-16777216" icon="icon2"
ID="85953eeb-b205-482b-9b4c-b6f8156251e9" Name="item1" />
<e:TreeItem color="-1" icon="icon1"
ID="13140ccc-8c5e-4471-ba30-a51426bbd605" Name="item2" />
<e:TreeItem parent="b141e55a-b043-49be-b2d9-ce669e116362"
color="-8388480" icon="icon3"
ID="b141e55a-b043-49be-b2d9-ce669e116362" Name="item11" />
</e:TreeItemCollection>
生成changes.xml 会得到
<e:TreeItemCollection xmlns:e="elements" xmlns:o="versioning">
<e:TreeItem parent="e457617f-03fd-4948-9f83-304222f3ab0b"
o:parent="b141e55a-b043-49be-b2d9-ce669e116362"
ID="b141e55a-b043-49be-b2d9-ce669e116362" />
</e:TreeItemCollection>
优点
- 简单的 XML 序列化无法序列化递归结构,但是此库可以轻松地实现。
- 使用
DataTable
,您可以序列化递归结构,但是您应该通过读取手动解析引用。 - 使用
Configuration
API,您会遇到与DataTable
相同的情况。 - 引用的元素 ID 保存在序列化的 XML 中,这使得序列化的形式可读。
多个容器
到目前为止,我只序列化了一个容器 (List
)。 第二个项目显示了如何序列化两个容器。 原则上,我必须有第三个容器,Project2Space
,它包含其他两个容器。
因此,我将TreeItem
类分为两个类:TreeItem
和Style
。
public class StyleCollection: ElementList<Style>
{
}
public class Project2Space: ElementSpace
{
private StyleCollection _styles = new StyleCollection();
public StyleCollection Styles
{
get { return _styles; }
}
private TreeItemCollection _treeItems = new TreeItemCollection();
public TreeItemCollection TreeItems
{
get { return _treeItems; }
}
public Project2Space()
{
AddInnerElement(_styles);
AddInnerElement(_treeItems);
}
}
如您所见,关键是添加一个内部元素。 现在,您可以像以前一样使用元素。
Project2Space space = new Project2Space();
StyleCollection styles = space.Styles;
Style style1 = styles.Add("red icon 1");
style1.Color = Color.Red;
style1.Icon = "icon1";
Style style2 = styles.Add("black icon2");
style2.Color = Color.Black;
style2.Icon = "icon2";
TreeItemCollection collection = space.TreeItems;
TreeItem root = collection.Add("root");
root.Style = style1;
TreeItem item1 = collection.Add("item1");
item1.Style = style2;
TreeItem item2 = collection.Add("item2");
item2.Style = style2;
TreeItem item11 = collection.Add("item11");
item11.Parent = item11;
item11.Style = style1;
Writer.Write(space, "test.xml", false);
space.AcceptChanges();
item11.Parent = root;
item1.Style = style1;
Writer.Write(space, "changes.xml", true);
Project2Space testSpace = new Project2Space();
Reader.Read("test.xml", testSpace, null);
Reader.Read("changes.xml", testSpace, null);
Style redStyle = testSpace.Find(style1.ID.Value) as Style;
TreeItem test_item1 = testSpace.TreeItems.Find(item1.Name);
if (test_item1.Style == redStyle)
Console.WriteLine("Perfect");
生成test.xml 会得到
<e:Project2Space xmlns:e="elements">
<e:StyleCollection ID="202142ea-8dbf-4ebe-a2f8-51306bc367bd">
<e:Style color="-65536" icon="icon1"
ID="bd806e02-5d37-457c-a341-862abef580f5" Name="red icon 1" />
<e:Style color="-16777216" icon="icon2"
ID="e88adf6e-63b3-4106-953c-09c7d441fbc3" Name="black icon2" />
</e:StyleCollection>
<e:TreeItemCollection ID="280e1811-7bc9-44ed-8c1c-2e492857da12">
<e:TreeItem style="bd806e02-5d37-457c-a341-862abef580f5"
ID="70f42380-6484-4b91-bb4b-3a67de6d5541" Name="root" />
<e:TreeItem style="e88adf6e-63b3-4106-953c-09c7d441fbc3"
ID="5f226519-bb60-4e52-9c09-ea095a3c74d8" Name="item1" />
<e:TreeItem style="e88adf6e-63b3-4106-953c-09c7d441fbc3"
ID="73aa0abb-a1ac-4850-a778-7970cf3a3069" Name="item2" />
<e:TreeItem parent="ab69de5f-3bcf-4f05-b3e3-0c961b57b0a5"
style="bd806e02-5d37-457c-a341-862abef580f5"
ID="ab69de5f-3bcf-4f05-b3e3-0c961b57b0a5" Name="item11" />
</e:TreeItemCollection>
</e:Project2Space>
生成changes.xml 会得到
<e:Project2Space xmlns:e="elements" xmlns:o="versioning">
<e:TreeItemCollection ID="280e1811-7bc9-44ed-8c1c-2e492857da12">
<e:TreeItem style="bd806e02-5d37-457c-a341-862abef580f5"
o:style="e88adf6e-63b3-4106-953c-09c7d441fbc3"
ID="5f226519-bb60-4e52-9c09-ea095a3c74d8" />
<e:TreeItem parent="70f42380-6484-4b91-bb4b-3a67de6d5541"
o:parent="ab69de5f-3bcf-4f05-b3e3-0c961b57b0a5"
ID="ab69de5f-3bcf-4f05-b3e3-0c961b57b0a5" />
</e:TreeItemCollection>
</e:Project2Space>
嵌套结构
在前面的演示中,我展示了列表元素。 但是,有时需要管理结构化数据。 因此,在第三个演示中,我将介绍LogInfo
元素。
[Serialization("Logging",null,true)]
public class LogInfo : Element
{
private const string PassswordName = "pswd";
private string _password;
[Serialization(PassswordName,
SerializationSettings.Encrypt |
SerializationSettings.SerializeAsAttribute)]
public string Password
{
get { return _password; }
set
{
if (_password != value)
{
LogChange(PassswordName, _password, value);
_password = value;
}
}
}
...
}
在此代码中,您可以看到该库的几个其他功能。 首先,您可以强制写入器使用SerializationSettings.Encrypt
加密string
属性的内容。 其次,使用[Serialization("Logging",null,true)]
属性,您可以阻止写入器写入元素 ID。 在这种情况下,我仅在Project2Space
元素中使用LogInfo
,因此我不需要通过 ID 标识该元素。 将LogInfo
包含在配置中非常容易。
public class Project2Space: ElementSpace
{
...
private LogInfo _logInfo = new LogInfo();
public LogInfo LogInfo
{
get { return _logInfo; }
}
public Project2Space()
{
...
AddInnerElement(_logInfo);
}
}
生成test.xml 会得到
<e:Project2Space xmlns:e="elements">
...
<e:Logging pswd="D0wfLkJuLmkoS5F4+X2JGg==" user="username" />
</e:Project2Space>
您可以看到Password
属性被序列化为psw
属性,并且内容已被加密。
其余部分
该库还允许您将序列化的 XML 压缩为有效的 ZIP。
public static void WriteZip(IElement element, string zipFileName,
string fileName, bool writeChanges, string password)
public static void ReadZip(string fileName, IElement element,
Logger logger, string password)
Logger
通过读取和写入配置来收集错误和提示。 通常,您会获得未解决的引用的列表。 另外,如果您合并配置和更改日志中的旧值,则它与实例中的值不对应。 如果您已经有了类层次结构,则可以通过实现IElement
接口来使用该库。
如果您不想序列化所有元素,则可以实现IFilter
接口。
public interface IFilterElement
{
bool IsFiltered();
}
如果您不想序列化某些元素的属性,则可以按以下方式将其过滤掉
[Serialization("Prop1", "Prop1Filter")]
public string Prop1
...
public bool Prop1Filter
历史
- 2007 年 6 月 19 日 -- 发布原始版本
许可证
本文没有附加明确的许可,但可能在文章文本或下载文件中包含使用条款。 如有疑问,请通过下面的讨论区与作者联系。 可以在此处找到作者可能使用的许可证列表。