`

C# 轻量级解析XML——XMLParser

阅读更多

    C# 轻量级解析XML——XMLParser

       记得之前写过一篇关于XML解析的博客(猛点查看),之前是因为发现Xpath这个类似SQL语句的字符串解析XML,觉得很惊奇,遂有了那篇文章。用XMLParser解析XML文件,是因为工作Unity发布WinPhone版本是不支持System.xml这个类库,这里的确有点想吐槽下(Microsoft在自家院里怎么没有做兼容)。所以我就google下,才找到了XMLparser这个类库(其实就三个.cs文件)。

       这里介绍下XMLParser的原理,XMLParser应就三个类文件 XMLParser,XMLNode,XMLNodeList,顾名思义,XMLParser就是解析XML的实现类(基于字符匹配解析的,具体细节可以看代码,我是没心思看这个了,太绕了),XMLNode就是将解析出来的“项”存储为XMLNode,其实就是一个Hashtable,XMLNodeList就不用多说了。查询的时候就是需要查询项的“路径”字符串传入XMLNode(Hashtable)查找返回。

    写到这里突然想到写这篇博客的另外一个理由:XMLParser这个类库是我找到的,但是是给项目其他同事用的,然后我那个同事一直说解析不到,妈蛋,会不会用呀,然后我就无语写了几行例子教程。

    所以直接附上这几行教程:

string str = File.ReadAllText(@"config.xml", Encoding.UTF8);   //读取XML文件
            //MessageBox.Show(str);
            XMLParser xmlParser = new XMLParser();
            XMLNode xn = xmlParser.Parse(str);
            server = xn.GetValue("items>0>server>0>_text");
            database = xn.GetValue("items>0>database>0>_text");
            XMLNode temp=xn.GetNode("items>0>res>0");
            string basePath=temp.GetValue("@basePath");//或直接 basePath=xn.GetValue("items>0>res>0>@basePath");

 当然xml文件内容为:

<?xml version="1.0" encoding="utf-8" ?>
<items>
  <server>192.168.52.148</server>
  <database>world</database>
  <port>3306</port>
  <uid>wtx</uid>
  <password>123456</password>
  <res basePath="d:\Resources" language="zh_CN" />
 </items>

 得到的解析结果是 

server=192.168.52.148 ;  database=world;  basePath=d:\Resources

 

 

最后附上XMLParser的三个文件凑下篇幅:

XMLParser:

/*
 * UnityScript Lightweight XML Parser
 * by Fraser McCormick (unityscripts@roguishness.com)
 * http://twitter.com/flimgoblin
 * http://www.roguishness.com/unity/
 *
 * You may use this script under the terms of either the MIT License 
 * or the Gnu Lesser General Public License (LGPL) Version 3. 
 * See:
 * http://www.roguishness.com/unity/lgpl-3.0-standalone.html
 * http://www.roguishness.com/unity/gpl-3.0-standalone.html
 * or
 * http://www.roguishness.com/unity/MIT-license.txt
 */
  
/* Usage:
 * parser=new XMLParser();
 * var node=parser.Parse("<example><value type=\"String\">Foobar</value><value type=\"Int\">3</value></example>");
 * 
 * Nodes are Boo.Lang.Hash values with text content in "_text" field, other attributes
 * in "@attribute" and any child nodes listed in an array of their nodename.
 * 
 * any XML meta tags <? .. ?> are ignored as are comments <!-- ... -->
 * any CDATA is bundled into the "_text" attribute of its containing node.
 *
 * e.g. the above XML is parsed to:
 * node={ "example": 
 *			[ 
 *			   { "_text":"", 
 *				  "value": [ { "_text":"Foobar", "@type":"String"}, {"_text":"3", "@type":"Int"}]
 *			   } 
 *			],
 *		  "_text":""
 *     }
 *		  
 */

using System.Collections;
 
public class XMLParser
{	
	private char LT     = '<';
	private char GT     = '>';
	private char SPACE  = ' ';
	private char QUOTE  = '"';
	private char QUOTE2 = '\'';
	private char SLASH  = '/';
	private char QMARK  = '?';
	private char EQUALS = '=';
	private char EXCLAMATION = '!';
	private char DASH   = '-';
	//private char SQL  = '[';
	private char SQR    = ']';
	
	public  XMLNode Parse(string content)
	{
		XMLNode rootNode = new XMLNode();
		rootNode["_text"] = "";

		string nodeContents = "";
		
		bool inElement = false;
		bool collectNodeName = false;
		bool collectAttributeName = false;
		bool collectAttributeValue = false;
		bool quoted = false;
		string attName = "";
		string attValue = "";
		string nodeName = "";
		string textValue = "";
		
		bool inMetaTag = false;
		bool inComment = false;
		bool inCDATA = false;
		
		XMLNodeList parents = new XMLNodeList();
		
		XMLNode currentNode = rootNode;
		
		for (int i = 0; i < content.Length; i++)
		{
			char c = content[i];
			char cn = '~';  // unused char
			char cnn = '~'; // unused char
			char cp = '~';  // unused char
			
			if ((i + 1) < content.Length) cn = content[i + 1]; 
			if ((i + 2) < content.Length) cnn = content[i + 2]; 
			if (i > 0) cp = content[i - 1];
					
			if (inMetaTag)
			{
				if (c == QMARK && cn == GT)
				{
					inMetaTag = false;
					i++;
				}
				
				continue;
			}
			else
			{
				if (!quoted && c == LT && cn == QMARK)
				{
					inMetaTag = true;
					continue;	
				}	
			}
			
			if (inComment)
			{
				if (cp == DASH && c == DASH && cn == GT)
				{
					inComment = false;
					i++;
				}
				
				continue;	
			}
			else
			{
				if (!quoted && c == LT && cn == EXCLAMATION)
				{
					
					if (content.Length > i + 9 && content.Substring(i, 9) == "<![CDATA[")
					{
						inCDATA = true;
						i += 8;
					}
					else
					{					
						inComment = true;
					}
					
					continue;	
				}
			}
			
			if (inCDATA)
			{
				if (c == SQR && cn == SQR && cnn == GT)
				{
					inCDATA = false;
					i += 2;
					continue;
				}
				
				textValue += c;
				continue;	
			}
			
			
			if (inElement)
			{
				if (collectNodeName)
				{
					if (c == SPACE)
					{
						collectNodeName = false;
					}
					else if (c == GT)
					{
						collectNodeName = false;
						inElement=false;
					}
					
			
		
					if (!collectNodeName && nodeName.Length > 0)
					{
						if (nodeName[0] == SLASH)
						{
							// close tag
							if (textValue.Length > 0)
							{
								currentNode["_text"] += textValue;
							}
					
							textValue = "";
							nodeName = "";
							currentNode = parents.Pop();
						}
						else
						{
							if (textValue.Length > 0)
							{
								currentNode["_text"] += textValue;
							}
							
							textValue = "";	
							XMLNode newNode = new XMLNode();
							newNode["_text"] = "";
							newNode["_name"] = nodeName;
							
							if (currentNode[nodeName] == null)
							{
								currentNode[nodeName] = new XMLNodeList();	
							}
							
							XMLNodeList a = (XMLNodeList)currentNode[nodeName];
							a.Push(newNode);	
							parents.Push(currentNode);
							currentNode=newNode;
							nodeName="";
						}
					}
					else
					{
						nodeName += c;	
					}
				} 
				else
				{
					if(!quoted && c == SLASH && cn == GT)
					{
						inElement = false;
						collectAttributeName = false;
						collectAttributeValue = false;	
						if (attName.Length > 0)
						{
							if (attValue.Length > 0)
							{
								currentNode["@" + attName] = attValue;								
							}
							else
							{
								currentNode["@" + attName] = true;								
							}
						}
						
						i++;
						currentNode = parents.Pop();
						attName = "";
						attValue = "";		
					}
					else if (!quoted && c == GT)
					{
						inElement = false;
						collectAttributeName = false;
						collectAttributeValue = false;	
						if (attName.Length > 0)
						{
							currentNode["@" + attName] = attValue;							
						}
						
						attName = "";
						attValue = "";	
					}
					else
					{
						if (collectAttributeName)
						{
							if (c == SPACE || c == EQUALS)
							{
								collectAttributeName = false;	
								collectAttributeValue = true;
							}
							else
							{
								attName += c;
							}
						}
						else if (collectAttributeValue)
						{
							if (c == QUOTE || c == QUOTE2)
							{
								if (quoted)
								{
									collectAttributeValue = false;
									currentNode["@" + attName] = attValue;								
									attValue = "";
									attName = "";
									quoted = false;
								}
								else
								{
									quoted = true;	
								}
							}
							else
							{
								if (quoted)
								{
									attValue += c;	
								}
								else
								{
									if (c == SPACE)
									{
										collectAttributeValue = false;	
										currentNode["@" + attName] = attValue;								
										attValue = "";
										attName = "";
									}	
								}
							}
						}
						else if (c == SPACE)
						{
						
						}
						else
						{
							collectAttributeName = true;							
							attName = "" + c;
							attValue = "";
							quoted = false;		
						}	
					}
				}
			}
			else
			{
				if (c == LT)
				{
					inElement = true;
					collectNodeName = true;	
				}
				else
				{
					textValue += c;	
				}	
			}
		}
	
		return rootNode;
	}
}

 XMLNode:

using System.Collections;

public class XMLNode: Hashtable
{
	public XMLNodeList GetNodeList(string path)
	{
		return GetObject(path) as XMLNodeList;
	}
	
	public XMLNode GetNode(string path)
	{
		return GetObject(path) as XMLNode;
	}
	
	public string GetValue(string path)
	{
		return GetObject(path) as string;
	}
	
	private object GetObject(string path)
	{
		string[] bits = path.Split('>');
		XMLNode currentNode = this;
		XMLNodeList currentNodeList = null;
		bool listMode = false;
		object ob;
		
		for (int i = 0; i < bits.Length; i++)
		{
			 if (listMode)
             {
                currentNode = (XMLNode)currentNodeList[int.Parse(bits[i])];
                ob = currentNode;
				listMode = false;
			 }
			 else
			 {
				ob = currentNode[bits[i]];
				
				if (ob is ArrayList)
				{
					currentNodeList = (XMLNodeList)(ob as ArrayList);
					listMode = true;
				}
				else
				{
					// reached a leaf node/attribute
					if (i != (bits.Length - 1))
					{
						// unexpected leaf node
						string actualPath = "";
						for (int j = 0; j <= i; j++)
						{
							actualPath = actualPath + ">" + bits[j];
						}
						
						//Debug.Log("xml path search truncated. Wanted: " + path + " got: " + actualPath);
					}
					
					return ob;
				}
			 }
		}
		
		if (listMode) 
			return currentNodeList;
		else 
			return currentNode;
	}
}

 XMLNodeList:

using System.Collections;

public class XMLNodeList: ArrayList 
{
	public XMLNode Pop()
	{
		XMLNode item = null;
	
		item = (XMLNode)this[this.Count - 1];
		this.Remove(item);
		
		return item;
	}
	
	public int Push(XMLNode item)
	{
		Add(item);
		
		return this.Count;
	}
}

 

        就是这么简单(代码可以粘贴复制下来琢磨),我觉得最爽的是不用看C# 微软的那套api,然后使用起来还有跟剥笋一样一层一层进入,挺费事,一点快感都没有。当然XMLParser最大的缺憾是不能写入,看需求吧!

 

        最后还是说下自己的感悟:很久没有写博客了,虽然写的东西都很渣,但是我觉得写博客,可以给自己一个整理的过程,堆积了一堆东西没有写,最近项目比较闲,所以今天有用了会XMLParser,就果断了。

        如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。

        转载请在文首注明出处:http://dsqiu.iteye.com/admin/blogs/1964401

更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风)

 

参考:

①UnityScript Lightweight XML Parser: http://www.roguishness.com/unity/

 

1
0
分享到:
评论
1 楼 liuweihug 2014-05-07  
C# Linq使用XDocument读取Xml文件并形成结构树数据(json) 
http://www.suchso.com/projecteactual/Csharp-Linq-XDocument-Xml-File-Tree-Data.html

相关推荐

    XML读取以及解析

    - **PULL解析**:类似于SAX,也采用事件驱动,但更轻量级,适合移动设备或资源受限的环境。 3. **解析库**: 在不同的编程语言中,有许多成熟的XML解析库,例如: - Java:DOM4J、JAXB、Java的内置`javax.xml....

    xml json互相转化

    XML提供了更复杂的数据表示能力,而JSON则更适合轻量级的交互和快速的网络传输。在处理大量数据时,JSON通常比XML更高效,因为它的格式更紧凑。 总之,理解和掌握XML与JSON之间的转换对于任何IT专业人员来说都是至...

    IOS XML类型转JSON类型

    2. JSON:是一种轻量级的数据交换格式,它采用完全独立于语言的文本格式,但也使用了类似于C家族语言的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。JSON的数据结构主要由对象(键值对)和数组构成,...

    xml格式数据和json相互转换的源码

    XML是一种结构化标记语言,适用于描述复杂的数据结构,而JSON则更简洁,通常用于轻量级的Web服务和浏览器之间的数据交互。本篇文章将深入探讨XML与JSON之间的转换,以及如何在代码中实现这种转换。 首先,让我们...

    antlr4-json-parser.zip

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript编程语言的一个子集,但JSON是独立于语言的,并且通常用于替代XML作为数据传输格式...

    JSON-Parser:JSON解析器

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, ...

    Parser_lightshot:ncx的简单解析器

    标题中的"Parser_lightshot"指的是一个轻量级的解析器,专门用于处理"ncx"文件格式。在电子书领域,NCX(Navigation Control File for XML)是EPUB格式的一个组成部分,它类似于传统图书的目录页,包含了书籍的章节...

    parser

    - `org.json`:一个轻量级的JSON库,提供解析和生成JSON的功能。 3. **解析技术**: - **递归下降解析(Recursive Descent Parsing)**:这是基于上下文无关文法(Context-Free Grammar, CFG)的一种解析方法,...

    xlsx文件转json工具

    然而,随着Web应用程序和游戏开发的发展,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,也变得越来越普及。本文将围绕“xlsx文件转json工具”进行深入探讨,了解其工作原理、使用方法,并结合...

    Pck:解析器构建套件

    3. **Markdown**:Markdown是轻量级的文本格式语言,广泛用于编写文档和笔记。Pck可能包含Markdown解析器生成器,使得开发者能够轻松处理Markdown文本,将其转换成HTML或其他格式。 4. **C#**与**.NET**:这两者是...

    C#读写ini.rar

    ini文件是一种轻量级的文本格式,用于存储配置数据,通常包含键值对,结构简单,易于理解和编辑。 在C#中,没有内置的ini文件读写函数,但开发者可以通过第三方库或者自定义方法来实现这一功能。下面我们将深入探讨...

    解析json详解,教程

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它采用完全独立于语言的文本格式,但也使用了类似于C家族语言的习惯,包括C、C++、C#、Java、JavaScript、Perl、Python等。JSON易于人阅读和编写,...

    get_form winform获取表单

    而INI文件则是一种轻量级的配置文件格式,通常用于存储简单键值对。可以使用第三方库如`IniFile`来读写INI文件: ```csharp using IniParser; using IniParser.Model; // 保存控件信息到INI var fileParser = new ...

    JSON例子

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它采用完全独立于语言的文本格式,但也使用了类似于C家族语言(包括C、C++、C#、Java、JavaScript、Perl、Python等)的习惯,这使得JSON成为理想的...

    通过Android App调用网络服务

    - **REST(Representational State Transfer)**:一种轻量级的架构风格,通过HTTP方法(GET、POST、PUT、DELETE)操作资源。WCF支持创建RESTful服务,通常使用JSON或XML作为数据格式。 2. **在Android中调用Web...

    protobuf-net

    它是一种轻量级的序列化技术,旨在减少网络传输数据的大小,提高数据交换的效率,广泛应用于分布式系统、云计算、游戏开发等领域。该工具允许开发者将数据结构转化为二进制格式,以便在网络间高效地传输或者存储在...

Global site tag (gtag.js) - Google Analytics