我正在开发一个通用系统,该系统需要能够反序列化任意 XML,这意味着我事先并不知道标签/属性将在哪些标签/属性中出现。 XML文档。理想情况下,XML就像这样:
<a att="1">
<b />
</a>
会成为这样的对象:
new Tag { name = "a",
attributes = new Dictionary<string,string> {{"att", "1"}},
elements = new List<Tag> { new Tag { name = "b" } } }
如果所有内容都反序列化为字符串,那就完全没问了。
答案 0 :(得分:2)
根据建议,使用LINQ to XML,您可以从任意XML文件中解析和提取数据:
var xml = @"<?xml version=""1.0"" encoding=""utf-8""?><a id=""1"" name=""test"">an element<b>with sub-element</b></a>";
// load XML from string
var xmlDocument = XDocument.Parse(xml);
// OR load XML from file
//var xmlDocument = XDocument.Load(@"d:\temp\input.xml");
// find all elements of type b and in this case take the first one
var bNode = xmlDocument.Descendants("b").FirstOrDefault();
if (bNode != null)
{
Console.WriteLine(bNode.Value);
}
// find the first element of type a and take the attribute name (TODO error handling)
Console.WriteLine(xmlDocument.Element("a").Attribute("name").Value);
输出是:
with sub-element
test
您还可以非常轻松地将对象转换为XML文件:
// sample class
public class Entry
{
public string Name { get; set; }
public int Count { get; set; }
}
// create and fill the object
var entry = new Entry { Name = "test", Count = 10 };
// create xml container
var xmlToCreate = new XElement("entry",
new XAttribute("count", entry.Count),
new XElement("name", entry.Name));
// and save it
xmlToCreate.Save(@"d:\temp\test.xml");
新创建的XML文件如下所示:
<?xml version="1.0" encoding="utf-8"?>
<entry count="10">
<name>test</name>
</entry>
LINQ非常强大且易于使用(和IMO直观)。 This MSDN article通过良好的样本,可以很好地了解LINQ及其功能和能力范围。 LINQPad - minimalistic but very powerful IDE for .NET附带了非常好的内置LINQ to XML教程和示例。最后是list of all LINQ to XML extension methods at MSDN。
另一种可能性是使用XmlReader class来解析任意XML文件。在这里,您负责实现解析逻辑,因此有时可能很麻烦。使用XmlReader解析相同的输入文件如下所示:
public void parseUsingXmlReader(string xmlString)
{
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine(string.Format("Element - {0}", reader.Name));
if (reader.HasAttributes)
{
for (var i = 0; i < reader.AttributeCount; i++)
{
Console.WriteLine(string.Format("Attribute - {0}", reader.GetAttribute(i)));
}
reader.MoveToElement();
}
break;
case XmlNodeType.Text:
Console.WriteLine(string.Format("Element value - {0}", reader.Value));
break;
//case XmlNodeType.XmlDeclaration:
//case XmlNodeType.ProcessingInstruction:
// Console.WriteLine(reader.Name + " - " + reader.Value);
// break;
case XmlNodeType.Comment:
Console.WriteLine(reader.Value);
break;
case XmlNodeType.EndElement:
Console.WriteLine(reader.Value);
break;
}
}
}
}
// use the new function with the input from the first example
parseUsingXmlReader(xml);
输出结果为:
Element - a
Attribute - 1
Attribute - test
Element value - an element
Element - b
Element value - with sub-element
如您所见,您需要手动处理节点类型,当前位置,属性等。
答案 1 :(得分:0)
这里没有太多信息。作为Linq for XML方法的替代外部接口,您可以尝试动态方法。这是一个示例程序:
class Program {
static void Main(string[] args) {
var xmlstr =
@"<a att='1'>
<b attb='a b c'>
<c att2='text'>value</c>
</b>
</a>";
dynamic xml = new DynamicXml(xmlstr);
Console.WriteLine(xml.a[0].att);
Console.WriteLine(xml.a[0].b[0].attb);
Console.WriteLine(xml.a[0].b[0].c[0].att2);
}
public class DynamicXml: DynamicObject {
XElement _root;
IEnumerable<XElement> _xele;
public DynamicXml(string xml) {
var xdoc = XDocument.Parse(xml);
_root = xdoc.Root;
}
DynamicXml(XElement root) {
_root = root;
}
DynamicXml(XElement root, IEnumerable<XElement> xele) {
_root = root;
_xele = xele;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
// you should check binder.CallInfo, but for the example I'm assuming [n] where n is int type indexing
var idx = (int)indexes[0];
result = new DynamicXml(_xele.ElementAt(idx));
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var atr = _root.Attributes(binder.Name).FirstOrDefault();
if (atr != null) {
result = atr.Value;
return true;
}
var ele = _root.DescendantsAndSelf(binder.Name);
if (ele != null) {
result = new DynamicXml(_root, ele);
return true;
}
result = null;
return false;
}
}
}
需要注意的是,XML元素可以包含值和属性。你需要一种处理价值的方法。在上面的代码中,你可以使用像“Value”这样的特殊名称,但是你将无法处理同名的属性。