所以,出于某种原因,这看起来非常棘手。我想我已经尝试了所有我能想到的解决方案,但似乎没有一个能够接近我需要的结果。
说我有自定义XML。它是非结构化的,但有一个共同的"架构"即:
<holder id="1">
<name datatype="int">First Record</name>
<cost datatype="double">100.24</cost>
<service datatype="string" serviceID="12345">A custom service</service>
</holder>
<holder id="2">
<name datatype="int">secondRecord</name>
<cost datatype="double">3000.24</cost>
<service datatype="string" serviceID="9876">A custom service 2</service>
</holder>
我想要做的就是完成所有这些并将其解析为我的自定义类文件。 我有一个自定义的Xml节点(属性:名称(即&#34;成本&#34;,值,即#34; 100.24&#34;) 我在自定义xml Node类
中有一组属性(key / valuepair)任何想法如何解析这个xml?
答案 0 :(得分:1)
好吧,你可以选择一个简单的Tree系统来读取你的Xml,它不必知道任何关于XML的知识,可以用Item索引器设置属性,或者使用一些方法,并使用XmlReader你可以自己快速浏览节点
但是,从我的评论中你也可以看到,对你来说,你的问题并不完全清楚(你尝试了什么,失败了什么,最终结果应该是什么)
我已经设置了一些创建树的类,可以注册一些属性(ITreeNode),拥有一个父母并且有一个孩子(我猜,因为你的帖子的这部分也缺失了,它是类似的东西你的自定义XmlNode)
基本上,这是自定义XmlParser
public class TreeNodeParser
{
public T ReadNode<T>(T parent, XmlReader reader)
where T: class, ITreeNode, new()
{
if (reader.NodeType == XmlNodeType.Whitespace)
{
return null;
}
T subNode = new T();
while (reader.NodeType != XmlNodeType.Element && reader.Read())
{
}
subNode.Tag = reader.Name;
subNode.Parent = parent;
if (reader.AttributeCount > 0)
{
reader.MoveToFirstAttribute();
do
{
subNode.SetAttribute(reader.Name, reader.Value);
} while (reader.MoveToNextAttribute());
}
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement)
{
if (string.Equals(subNode.Tag, reader.Name))
{
break;
}
continue;
}
if (reader.NodeType == XmlNodeType.Element)
{
T child = ReadNode(subNode, reader);
if (child != null)
{
subNode.Children.Add(child);
}
continue;
}
if (reader.NodeType == XmlNodeType.Text)
{
subNode.ValueAsString = reader.Value;
continue;
}
}
return subNode;
}
public T FromStream<T>(Stream stream)
where T : class, ITreeNode, new()
{
T result = default(T);
using (XmlReader reader = new XmlTextReader(stream))
{
while (reader.Read())
{
T child = ReadNode(result, reader);
if (child != null)
{
result = child;
}
}
}
return result;
}
}
你可以把它传递给它,它可以读取所有元素和所有属性(并忽略空白元素)。因为xml本质上是一个树,所以你得到rootNode(如果有的话)
例如,这是测试主程序(控制台)
static void Main(string[] args)
{
TreeNodeParser nodeParser = new TreeNodeParser();
using (Stream readStream = new FileStream(Path.Combine(Environment.CurrentDirectory, "TestFile.xml"), FileMode.Open, FileAccess.Read))
{
var node = nodeParser.FromStream<Node>(readStream);
Console.WriteLine("{0}", node.ToString());
}
Console.ReadLine();
}
实现TreeNode实现了以下ToString()
覆盖(因此您可以看到它不只是将值作为字符串读取;)):
public override string ToString()
{
string content = "", attributes = "";
foreach (var child in Children)
{
content += child;
}
if (!string.IsNullOrWhiteSpace(ValueAsString))
{
content += ValueAsString;
}
foreach (var entry in properties)
{
attributes += string.Format(" {0}=\"{1}\"", entry.Key, entry.Value);
}
if (string.IsNullOrWhiteSpace(content))
{
return string.Format("<{0}{2} />", this.Tag, content, attributes);
}
return string.Format("<{0}{2}>{1}</{0}>", this.Tag, content, attributes);
}
}
结果是
要使其工作,我必须将基本Xml更改为以下结构(至少一个根元素)
<?xml version="1.0" encoding="utf-8"?>
<ValueList>
<holder id="1">
<name datatype="int">First Record</name>
<cost datatype="double">100.24</cost>
<service datatype="string" serviceID="12345">A custom service</service>
</holder>
<holder id="2">
<name datatype="int">secondRecord</name>
<cost datatype="double">3000.24</cost>
<service datatype="string" serviceID="9876">A custom service 2</service>
</holder>
</ValueList>
ITreeNode的一个可能的界面可能是这样的(尽管你的自定义XmlNode不需要这样做,所以你可以在第一段代码中重构这个部分)
public interface IPropertyHolder
{
string this[string attributeName] { get; }
void SetAttribute(string attribute, string value);
string GetAttribute(string attribute);
}
public interface INodeParent<T>
{
IList<T> Children { get; }
}
public interface INodeChild<T>
{
T Parent { get; set; }
}
public interface INode
{
string Tag { get; set; }
string ValueAsString { get; set; }
object Value { get; }
}
public interface ITreeNode : INode, IPropertyHolder, INodeParent<ITreeNode>, INodeChild<ITreeNode>
{
}