PHP 的 SimpleXML 类让你可以使用对象操作的方法操作 XML, 这是非常方便的, 想一想, a->b 与 a.getChild('b') 哪个更方便. 因为在 C# 中需要操作简单的 XML, 所以我试图实现一个 C# 版的 SimpleXML. 因为 C# 是一种静态型语言, 无法动态地生成一个不存在的类的实例, 所以我使用哈希表(字典, Dictionary)来实现, 正由于 C# 支持索引器, 我的 C# 版的 SimpleXML 类似 PHP 的关联数组. 使用例子如下:
SimpleXml xml = new SimpleXml("<root><a>Hello World!</a></root>"); Console.WriteLine(xml["a"]); // Hello World!
完整的源码:
using System; using System.Collections.Generic; using System.Text; using System.Collections; using System.IO; using System.Xml; namespace Ideawu.P2P.Utils { /// <summary> /// 表示一个 XML 节点. 以关联数组的方式操作 XML, 类似 PHP 的 SimpleXML. /// </summary> public class SimpleXml : IEnumerable { private String name = ""; private String text = ""; /// <summary> /// 表明该节点是否是同名节点的列表. /// </summary> private bool isList = false; private Dictionary<string, SimpleXml> children = new Dictionary<String, SimpleXml>(); private Dictionary<string, string> attributes = new Dictionary<string, string>(); /// <summary> /// 创建一个空的 SimpleXml. /// </summary> public SimpleXml() { } /// <summary> /// 以指定的名称创建一个 SimpleXml. /// </summary> /// <param name="name">SimpleXml 的名称.</param> public SimpleXml(string name) { this.name = name; } /// <summary> /// 以指定的名称和文本内容创建一个 SimpleXml. /// </summary> /// <param name="name">SimpleXml 的名称.</param> /// <param name="text">SimpleXml 的文本内容.</param> public SimpleXml(string name, string text) { this.name = name; this.text = text; } /// <summary> /// 名称, 标签名. /// </summary> public String Name { get { return name; } set { name = value; } } /// <summary> /// 节点的文本(经过 HTML encode). /// </summary> public String Text { get { return text; } set { text = value; } } /// <summary> /// 表明该节点是否是同名节点的列表. /// </summary> public bool IsList { get { return isList; } } /// <summary> /// 获取指定名称的属性值. /// </summary> /// <param name="key">属性名</param> /// <returns>属性值. 如果不存在则为空.</returns> public string GetAttribute(String key) { string v = null; attributes.TryGetValue(key, out v); return v; } /// <summary> /// 为节点添加一个属性. /// </summary> /// <param name="key">属性名.</param> /// <param name="value">属性值.</param> public void SetAttribute(String key, String value) { attributes[key] = value; } /// <summary> /// 删除指定名称的属性. /// </summary> /// <param name="key">要删除的属性的名称.</param> public void RemoveAttribute(String key) { attributes.Remove(key); } /// <summary> /// 移除本节点的所有属性. /// </summary> public void RemoveAllAttribute() { attributes.Clear(); } /// <summary> /// 获取指定标签名的子节点. 如果要获取的子节点不存在, 则返回 null. /// 这和通过索引器获取不一样. /// </summary> /// <param name="name">子节点的标签名.</param> /// <returns>子节点的引用或者 null.</returns> public SimpleXml GetChild(string name) { SimpleXml c = null; children.TryGetValue(name, out c); return c; } /// <summary> /// 添加一个带有指定标签名和文本的子节点. /// </summary> public void AddChild(string name, string text) { SimpleXml node = new SimpleXml(name, text); this[name] = node; } /// <summary> /// 移除本节点的指定名称(标签名)的子节点. /// </summary> /// <param name="childName">要移除的子节点的标签名.</param> public void RemoveChild(string childName) { children.Remove(childName); } /// <summary> /// 移除本 SimpleXml 的所有子节点. /// </summary> public void RemoveAllChild() { children.Clear(); } /// <summary> /// 清除本 Simple 所对应的 XML 标签的所有属性和子节点, 但不包括标签本身. /// 效果和同时调用 RemoveAllChild 和 RemoveAllAttribute 一样. /// </summary> public void Clear() { children.Clear(); attributes.Clear(); } /// <summary> /// 根据子节点的标签名获取子节点. /// </summary> /// <param name="childName"></param> /// <returns></returns> public SimpleXml this[string childName] { get { SimpleXml obj; if (!children.TryGetValue(childName, out obj)) { obj = new SimpleXml(); // 让空的节点名表示节点不存在. 而返回一个 SimpleXml 又可以使不抛出 NullReferenceException. //obj.name = childName; } return obj; } set { SimpleXml obj; if (!children.TryGetValue(childName, out obj)) { children[childName] = value; } else { // 如果存在相同名字的节点, 创建一个列表类型的节点, 包含所有这些同名节点, // 在内部以 0, 1, 2...命名. /** * 例如: <doc><bs><b/><b/></bs></doc> 可以这样迭代: * foreach(n in xml["bs"]){} 或者 foreach(n in xml["bs"]["b"]){} */ if (!obj.isList) { SimpleXml list = new SimpleXml(); list.isList = true; list.name = obj.name; list.text = obj.text; children[childName] = list; list.children["0"] = obj; list.children["1"] = value; } else { obj.children[obj.children.Count.ToString()] = value; } } } } #region IEnumerable 成员 /// <summary> /// 本 SimpleXml 的所有子节点的迭代. /// </summary> public IEnumerator GetEnumerator() { foreach (SimpleXml obj in children.Values) { if (obj.isList && !this.isList) { foreach (SimpleXml c in obj.children.Values) { yield return c; } } else { this.GetEnumerator(); yield return obj; } } } #endregion /// <summary> /// 返回本节点的名称(标签名). /// </summary> /// <returns>本节点的名称(标签名).</returns> public override String ToString() { return text; } /// <summary> /// 将本 SimpleXml 转换成 XML 字符串. /// </summary> /// <returns>XML 字符串表示的 SimpleXml.</returns> public string AsXml() { StringBuilder sb = new StringBuilder(); AsXml(this, sb); return sb.ToString(); } /// <summary> /// 将本 SimpleXml 所表示的 XML 文本写入到 StringBuilder 中. /// </summary> /// <param name="sb">要写入的 StringBuilder.</param> public void WriteTo(StringBuilder sb) { AsXml(this, sb); } private void AsXml(SimpleXml node, StringBuilder sb) { sb.Append("<" + node.name); if (node.attributes.Count > 0) { foreach (KeyValuePair<String, String> kv in node.attributes) { sb.Append(String.Format(" {0}=\"{1}\"", kv.Key, kv.Value)); } } sb.Append(">"); sb.Append(System.Web.HttpUtility.HtmlEncode(node.text)); foreach (SimpleXml child in node.children.Values) { if (child.isList) { foreach (SimpleXml cc in child) { AsXml(cc, sb); } } else { AsXml(child, sb); } } sb.Append("</" + node.name + ">"); } /// <summary> /// 从指定的流中载入 XML 文档来构建本 SimpleXml. /// </summary> /// <param name="stream">要载入的流.</param> public void Load(Stream stream) { XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(stream); this.Load(xmldoc); } /// <summary> /// 从指定的 XmlDocument 实例中载入 XML 文档来构建本 SimpleXml. /// </summary> /// <param name="xmldoc">要载入的 XmlDocument 实例.</param> public void Load(XmlDocument xmldoc) { XmlElement e = xmldoc.DocumentElement; SimpleXml node = LoadXmlElement(xmldoc.DocumentElement); this.name = node.name; this.text = node.text; this.children = node.children; this.attributes = node.attributes; } /// <summary> /// 从指定的字符串中载入 XML 文档来构建本 SimpleXml. /// </summary> /// <param name="stream">要载入的字符串.</param> public void LoadXml(string xmlstr) { XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlstr); this.Load(doc); } private SimpleXml LoadXmlElement(XmlElement e) { SimpleXml node = new SimpleXml(); node.name = e.Name; if (e.HasAttributes) { foreach (XmlAttribute attr in e.Attributes) { node.attributes[attr.Name] = attr.Value; } } if (e.HasChildNodes) { foreach (XmlNode c in e.ChildNodes) { switch (c.NodeType) { case XmlNodeType.CDATA: case XmlNodeType.Text: node.text += c.Value; break; case XmlNodeType.Element: SimpleXml child = LoadXmlElement((XmlElement)c); node[child.name] = child; break; } } } return node; } } }