天天看點

Unity中XMLParser的使用

C# 輕量級解析XML——XMLParser

用XMLParser解析XML檔案,是因為工作Unity釋出WinPhone版本是不支援System.xml這個類庫
           
XMLparser這個類庫(其實就三個.cs檔案)。

這裡介紹下XMLParser的原理,XMLParser應就三個類檔案 XMLParser,XMLNode,XMLNodeList,顧名思義,XMLParser就是解析XML的實作類(基于字元比對解析的,具體細節可以看代碼,我是沒心思看這個了,太繞了),XMLNode就是将解析出來的“項”存儲為XMLNode,其實就是一個Hashtable,XMLNodeList就不用多說了。查詢的時候就是需要查詢項的“路徑”字元串傳入XMLNode(Hashtable)查找傳回。

是以直接附上這幾行教程:

C#代碼  
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");  
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代碼  
<?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>  
<?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>
 得到的解析結果是 

Xml代碼  
server=192.168.52.148 ;  database=world;  basePath=d:\Resources  
server=192.168.52.148 ;  database=world;  basePath=d:\Resources
 

 

最後附上XMLParser的三個檔案湊下篇幅:
/*
 * UnityScript Lightweight XML Parser
 * by Fraser McCormick ([email protected])
 * 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":""
 *     }
 *		  
 */ 
 
 
XMLParser:
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:
C#代碼  
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:
C#代碼  
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;   
    }   
}  

當然XMLParser最大的缺憾是不能寫入,看需求吧!

參考:

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