首先,我受限于 .NET 2.0,因此 LINQ 对我来说不是一个选择(尽管我很想看到一个 LINQ 解决方案作为推动项目迁移到 .NET 3.5 的素材,如果它很容易的话)。
我有一个 XSD,它在构建时通过 xsd.exe 转换为一组 C# 类。在运行时,一个 XML 文件被加载并反序列化到 C# 类中(此时发生验证)。然后,我需要将该内存配置对象(包括在导入 XML 文件期间填充的默认值)转换为键值对字典。
我希望字典键是值的点分隔路径。属性值和元素文本将被视为值,其他所有内容都是其中的关键。
例如,想象以下 XML 文件:
<rootNode>
<foo enabled="true"/>
<bar enabled="false" myAttribute="5.6">
<baz>Some Text</baz>
<baz>Some other text.</baz>
</bar>
</rootNode>
将变成带有以下键的字典:
"rootNode.foo.enabled" = (Boolean)true
"rootNode.bar.enabled" = (Boolean)false
"rootNode.bar.myAttribute" = (Float)5.6
"rootNode.bar.baz" = List<String> { "Some Text", "Some other text." }
值得注意的是,rootNode 被忽略不是因为它很特殊,而是因为它没有文本或属性。此外,字典是正确键入的对象字典(这已经在反序列化中完成,这是我想使用 C# 对象而不是直接使用 XML 的原因之一)。
有趣的是,xsd.exe 创建的对象已经非常接近我想要的形式。类名类似于 rootNodeFoo,上面有一个名为 myAttribute 的浮点字段。
我考虑过但不确定如何进行的一件事是使用反射来迭代对象树并使用每个对象的类的名称来确定节点的名称(我可能需要调整大小写一点点)。问题在于,它感觉像是一个错误的解决方案,因为我已经可以访问一个反序列化器,它应该能够为我完成所有这些工作,而且速度要快得多。
另一种选择是使用 XSLT 将数据直接序列化为我想要的格式。这里的问题是我的 XSLT 知识是有限的,我相信(如果我错了,请纠正我)我会在路上输掉打字(一切都将是一个字符串)所以我将不得不再次手动反序列化以获得类型退出(这次没有使用 .NET 反序列化程序时得到的 XSD 验证)。
万一这很重要,我用来从 XML 文件中获取配置对象的调用是这样的:
var rootNode = new XmlRootAttribute();
rootNode.ElementName = "rootNode";
rootNode.Namespace = "urn:myNamespace";
var serializer = new XmlSerializer(typeof(rootNode), rootNode);
using (var reader = new StringReader(xmlString))
{
var deserializedObject = (rootNode)serializer.Deserialize(reader);
}