从未定义的XML获取所有节点,值和节点属性

时间:2015-01-26 21:59:05

标签: c# xml

所以,出于某种原因,这看起来非常棘手。我想我已经尝试了所有我能想到的解决方案,但似乎没有一个能够接近我需要的结果。

说我有自定义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?

1 个答案:

答案 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);
}

}

结果是

Example output of Custom XmlReader

要使其工作,我必须将基本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>
{
}