Unity引擎下最快的Xml讀取器:UnityRapidXml


      近期發現無論是系統的System.Xml還是Mono.Xml,其實都有這樣或者那樣的問題,所以決定自己搞一個快一點的xml parse.以前在C++里用過rapidxml,這個確實是神一般的存在,速度那是相當快,所以設想能否直接包裝一下,然后讓它可以在unity中使用呢?

      實測了一下,確定是可行的,所以把代碼放到了github上,github上的代碼應該一直都是比較新的:https://github.com/sczybt/UnityRapidXml

      

 

      可以看到在parse上,有至少10倍的速度優勢.這些測試性能的代碼可以在XmlPerformanceTests中找到.

      下面是簡單訪問數據的性能對比:

 

      可以看到差距並不大,由於存在着托管與native的轉換,所以UnityRapidXml並沒有優勢.但是一旦發生復雜搜索的時候,還是有優勢的,另外UnityRapidXml內置了獲取屬性值針對各個類型的接口,這樣字符串到bool/int/float等數據的轉換在native層完成,這樣效率更高.

     下面直接放目前最新的代碼,以后代碼更新不更新下面的代碼,需要最新的代碼建議去github上面取.

     RapidXml.cs

//
using System;
using System.Collections.Generic; using System.Runtime.InteropServices; using System.Diagnostics; namespace RapidXml { // Attribute public struct NodeAttribute { public RapidXmlParser Document; public IntPtr NativeAttrPtr; [Conditional("UNITY_EDITOR")] public static void EditorAssert(bool bInCondition) { if (!bInCondition) { UnityEngine.Debug.DebugBreak(); } } public bool IsValid() { return Document != null && NativeAttrPtr != IntPtr.Zero; } public string GetName() { EditorAssert(IsValid()); IntPtr Result = RapidXmlParser.GetAttributeNamePtr(Document.NativeDocumentPtr, NativeAttrPtr); return Result != IntPtr.Zero ? Marshal.PtrToStringAnsi(Result) : ""; } public string GetValue() { EditorAssert(IsValid()); IntPtr Result = RapidXmlParser.GetAttributeValuePtr(Document.NativeDocumentPtr, NativeAttrPtr); return Result != IntPtr.Zero ? Marshal.PtrToStringAnsi(Result) : ""; } public bool GetBool() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueBool(Document.NativeDocumentPtr, NativeAttrPtr); } public int GetInt() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueInt(Document.NativeDocumentPtr, NativeAttrPtr); } public uint GetUInt() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueUInt(Document.NativeDocumentPtr, NativeAttrPtr); } public Int64 GetInt64() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueInt64(Document.NativeDocumentPtr, NativeAttrPtr); } public UInt64 GetUInt64() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueUInt(Document.NativeDocumentPtr, NativeAttrPtr); } public float GetFloat() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueFloat(Document.NativeDocumentPtr, NativeAttrPtr); } public double GetDouble() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeValueDouble(Document.NativeDocumentPtr, NativeAttrPtr); } public NodeAttribute NextAttribute(string InName = null) { EditorAssert(IsValid()); NodeAttribute Attr = new NodeAttribute(); Attr.Document = this.Document; Attr.NativeAttrPtr = string.IsNullOrEmpty(InName) ? RapidXmlParser.NextAttributePtr(Document.NativeDocumentPtr, NativeAttrPtr) : RapidXmlParser.NextAttributePtrWithName(Document.NativeDocumentPtr, NativeAttrPtr, InName); return Attr; } } public struct NodeElement { public RapidXmlParser Document; public IntPtr NativeNodePtr; [Conditional("UNITY_EDITOR")] public static void EditorAssert(bool bInCondition) { if (!bInCondition) { UnityEngine.Debug.DebugBreak(); } } public bool IsValid() { return Document != null && NativeNodePtr != IntPtr.Zero; } public NodeElement FirstNode(string InName = null) { EditorAssert(IsValid()); NodeElement Element = new NodeElement(); Element.Document = Document; Element.NativeNodePtr = string.IsNullOrEmpty(InName) ? RapidXmlParser.FirstNodePtr(Document.NativeDocumentPtr, NativeNodePtr) : RapidXmlParser.FirstNodePtrWithName(Document.NativeDocumentPtr, NativeNodePtr, InName); return Element; } public NodeElement NextSibling(string InName = null) { EditorAssert(IsValid()); NodeElement Element = new NodeElement(); Element.Document = Document; Element.NativeNodePtr = string.IsNullOrEmpty(InName) ? RapidXmlParser.NextSiblingPtr(Document.NativeDocumentPtr, NativeNodePtr) : RapidXmlParser.NextSiblingPtrWithName(Document.NativeDocumentPtr, NativeNodePtr, InName); return Element; } public NodeAttribute FirstAttribute(string InName= null) { EditorAssert(IsValid()); NodeAttribute Attr = new NodeAttribute(); Attr.Document = this.Document; Attr.NativeAttrPtr = string.IsNullOrEmpty(InName) ? RapidXmlParser.FirstAttributePtr(Document.NativeDocumentPtr, NativeNodePtr) : RapidXmlParser.FirstAttributePtrWithName(Document.NativeDocumentPtr, NativeNodePtr, InName); return Attr; } public bool HasAttribute(String InName) { EditorAssert(IsValid()); return RapidXmlParser.HasAttribute(Document.NativeDocumentPtr, NativeNodePtr, InName); } public bool AttributeBool(String InName) { EditorAssert(IsValid()); return RapidXmlParser.AttributeBool(Document.NativeDocumentPtr, NativeNodePtr, InName); } public int AttributeInt(string InName) { EditorAssert(IsValid()); return RapidXmlParser.AttributeInt(Document.NativeDocumentPtr, NativeNodePtr, InName); } public uint AttributeUInt(string InName) { EditorAssert(IsValid()); return RapidXmlParser.AttributeUInt(Document.NativeDocumentPtr, NativeNodePtr, InName); } public float AttributeFloat(String InName) { EditorAssert(IsValid()); return RapidXmlParser.AttributeFloat(Document.NativeDocumentPtr, NativeNodePtr, InName); } public string AttributeString(string InName) { EditorAssert(IsValid()); IntPtr Result = RapidXmlParser.AttributeStringPtr(Document.NativeDocumentPtr, NativeNodePtr, InName); return Result != IntPtr.Zero ? Marshal.PtrToStringAnsi(Result) : ""; } // the same with AttributeString // created for compatible public string Attribute(string InName) { EditorAssert(IsValid()); IntPtr Result = RapidXmlParser.AttributeStringPtr(Document.NativeDocumentPtr, NativeNodePtr, InName); return Result != IntPtr.Zero ? Marshal.PtrToStringAnsi(Result) : ""; } public string GetName() { EditorAssert(IsValid()); IntPtr Result = RapidXmlParser.GetNodeTagPtr(Document.NativeDocumentPtr, NativeNodePtr); return Result != IntPtr.Zero ? Marshal.PtrToStringAnsi(Result) : ""; } public int GetChildNodeCount() { EditorAssert(IsValid()); return RapidXmlParser.GetChildNodeCount(Document.NativeDocumentPtr, NativeNodePtr); } public int GetAttributeCount() { EditorAssert(IsValid()); return RapidXmlParser.GetAttributeCount(Document.NativeDocumentPtr, NativeNodePtr); } } public class RapidXmlParser : IDisposable { public const string PluginName = "RapidXml"; public IntPtr NativeDocumentPtr = IntPtr.Zero; public void Load(string InContent) { NativeDocumentPtr = LoadFromString(InContent); string ErrorMessage = Marshal.PtrToStringAnsi(GetLastErrorMessage(NativeDocumentPtr)); if (!string.IsNullOrEmpty(ErrorMessage)) { throw new Exception(ErrorMessage); } } public void Dispose() { if (NativeDocumentPtr != IntPtr.Zero) { DisposeThis(NativeDocumentPtr); NativeDocumentPtr = IntPtr.Zero; } } public NodeElement FirstNode(string InName = null) { NodeElement Element = new NodeElement(); Element.Document = this; Element.NativeNodePtr = string.IsNullOrEmpty(InName) ? FirstNodePtr(NativeDocumentPtr, IntPtr.Zero) : FirstNodePtrWithName(NativeDocumentPtr, IntPtr.Zero, InName); return Element; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // internal use ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif private static extern IntPtr LoadFromString([MarshalAs(UnmanagedType.LPStr)]string InContent); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif private static extern IntPtr GetLastErrorMessage(IntPtr InDocumentNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif private static extern void DisposeThis(IntPtr InDocumentNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr FirstAttributePtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr FirstAttributePtrWithName(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr NextAttributePtr(IntPtr InDocumentNativePtr, IntPtr InAttrPtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr NextAttributePtrWithName(IntPtr InDocumentNativePtr, IntPtr InAttrPtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern bool HasAttribute(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern bool AttributeBool(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern int AttributeInt(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern uint AttributeUInt(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern Int64 AttributeInt64(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern UInt64 AttributeUInt64(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern float AttributeFloat(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern double AttributeDouble(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr AttributeStringPtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr FirstNodePtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr FirstNodePtrWithName(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr NextSiblingPtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr NextSiblingPtrWithName(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr, [MarshalAs(UnmanagedType.LPStr)]String InName); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr GetNodeTagPtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern int GetChildNodeCount(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern int GetAttributeCount(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr GetAttributeNamePtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern IntPtr GetAttributeValuePtr(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern bool GetAttributeValueBool(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern int GetAttributeValueInt(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern uint GetAttributeValueUInt(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern int GetAttributeValueInt64(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern uint GetAttributeValueUInt64(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern float GetAttributeValueFloat(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] #else [DllImport(PluginName, CallingConvention = CallingConvention.Cdecl)] #endif internal static extern double GetAttributeValueDouble(IntPtr InDocumentNativePtr, IntPtr InNodeNativePtr); } }

 

XmlPerformanceTests.cs

 

//
using UnityEngine;
using System; using System.Xml; using Mono.Xml; using RapidXml; using System.Security; public class XmlPerformanceTests : MonoBehaviour { [HideInInspector] public string XmlContent; RapidXmlParser xmlRapid = new RapidXmlParser(); XmlDocument xmlSystem = new XmlDocument(); SecurityParser xmlMono = new SecurityParser(); void Awake() { string path = System.IO.Path.Combine(Application.dataPath, @"Plugins/Xml/Tests/Test.xml"); Debug.Log(path); XmlContent = System.Text.Encoding.UTF8.GetString(System.IO.File.ReadAllBytes(path)); xmlRapid.Load(XmlContent); xmlSystem.LoadXml(XmlContent); xmlMono.LoadXml(XmlContent); } void OnDestroy() { xmlRapid.Dispose(); } void Update() { // TestParse();  TestVisit(); } void TestParse() { for (int i = 0; i < 10; ++i) { TestParse_Rapid(); TestParse_System(); TestParse_Mono(); } } void TestParse_Rapid() { Profiler.BeginSample("Rapid"); using (RapidXmlParser xml = new RapidXmlParser()) { xml.Load(XmlContent); } Profiler.EndSample(); } void TestParse_System() { Profiler.BeginSample("System"); XmlDocument xml = new XmlDocument(); xml.LoadXml(XmlContent); Profiler.EndSample(); } void TestParse_Mono() { Profiler.BeginSample("Mono"); SecurityParser xml = new SecurityParser(); xml.LoadXml(XmlContent); Profiler.EndSample(); } void TestVisit() { for( int i=0; i<10000; ++i ) { TestVisit_Rapid(); TestVisit_System(); TestVisit_Mono(); } } void TestVisit_Rapid() { Profiler.BeginSample("RapidVisit"); NodeElement RootNode = xmlRapid.FirstNode(); NodeElement Node = RootNode.FirstNode(); while( Node.IsValid() ) { // Debug.Log("Rapid " + Node.GetName());  Node = Node.NextSibling(); } Profiler.EndSample(); } void TestVisit_System() { Profiler.BeginSample("SystemVisit"); XmlNode RootElement = xmlSystem.ChildNodes[0]; var Iter = RootElement.GetEnumerator(); while( Iter.MoveNext() ) { XmlNode Node = Iter.Current as XmlNode; // Debug.Log("System " + Node.Name);  } Profiler.EndSample(); } void TestVisit_Mono() { Profiler.BeginSample("MonoVisit"); for ( int i=0; i< xmlMono.ToXml().Children.Count; ++i ) { SecurityElement Node = xmlMono.ToXml().Children[i] as SecurityElement; // Debug.Log("Mono " + Node.Tag);  } Profiler.EndSample(); } }

 

       下面是C++的代碼,這部分用於編譯成dll(windows),so(Android),也直接用於il2cpp之后的unity工程.

       RapidXmlNative.h

// simple Native Wrapper for c# Rapid Xml
#pragma once

#include <rapidxml/rapidxml.hpp> #include <string> #include <assert.h> #if defined(WIN32) || defined(_WIN32) #define EXPORT_API __declspec(dllexport) #else #define EXPORT_API #endif class RapidXmlNative { public: RapidXmlNative(const char* InContent) : Document(new rapidxml::xml_document<>()), LastErrorMessage("") { if (!InContent) { LastErrorMessage = "EmptyContent"; return; } Content = InContent; } ~RapidXmlNative() { if (Document) { delete Document; Document = NULL; } } bool Parse() { assert(Document); if (Content.empty()) { return false; } try { Document->parse<0>((char*)Content.c_str()); } catch (std::exception& e) { LastErrorMessage = e.what(); return false; } return true; } rapidxml::xml_document<>* GetDocument() const { return Document; } const std::string& GetLastErrorMessage() const { return LastErrorMessage; } private: // disable copyable RapidXmlNative(const RapidXmlNative&); RapidXmlNative& operator = (const RapidXmlNative&); protected: rapidxml::xml_document<>* Document; std::string Content; std::string LastErrorMessage; };

     

       RapidXml.cpp

//
// export for dll wrapper
//
#include "RapidXmlNative.h"

extern "C"
{
    EXPORT_API void* LoadFromString(const char* pInContent) { RapidXmlNative* Native = new RapidXmlNative(pInContent); Native->Parse(); return Native; } EXPORT_API const char* GetLastErrorMessage(void* InDocument) { assert(InDocument); RapidXmlNative* Native = (RapidXmlNative*)InDocument; return Native->GetLastErrorMessage().c_str(); } EXPORT_API void DisposeThis(void* InDocument) { assert(InDocument); if (InDocument) { RapidXmlNative* Native = (RapidXmlNative*)InDocument; delete Native; } } EXPORT_API void* FirstAttributePtr(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument && InNodePtr); if (!InNodePtr) { return NULL; } return InNodePtr->first_attribute(); } EXPORT_API void* FirstAttributePtrWithName(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr); if (!InNodePtr) { return NULL; } return InNodePtr->first_attribute(pName); } EXPORT_API void* NextAttributePtr(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr); if (!InAttrPtr) { return NULL; } return InAttrPtr->next_attribute(); } EXPORT_API void* NextAttributePtrWithName(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr, const char* pName) { assert(InDocument && InAttrPtr); if (!InAttrPtr) { return NULL; } return InAttrPtr->next_attribute(pName); } EXPORT_API bool HasAttribute(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return false; } return InNodePtr->first_attribute(pName) != NULL; } EXPORT_API bool AttributeBool(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return false; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return false; } char* Value = AttributeNode->value(); assert(Value != NULL); #ifdef _MSC_VER return _stricmp(Value, "true") == 0; #else return strcasecmp(Value, "true") == 0; #endif } EXPORT_API int AttributeInt(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return atoi(Value); } EXPORT_API unsigned AttributeUInt(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return strtoul(Value, NULL, 10); } EXPORT_API long long AttributeInt64(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return atoll(Value); } EXPORT_API unsigned long long AttributeUInt64(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return strtoull(Value, NULL, 10); } EXPORT_API float AttributeFloat(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return (float)atof(Value); } EXPORT_API double AttributeDouble(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return 0; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return 0; } char* Value = AttributeNode->value(); assert(Value != NULL); return atof(Value); } EXPORT_API void* AttributeStringPtr(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr && pName); if (!InDocument || !InNodePtr || !pName) { return NULL; } rapidxml::xml_attribute<>* AttributeNode = InNodePtr->first_attribute(pName); if (!AttributeNode) { return NULL; } char* Value = AttributeNode->value(); assert(Value != NULL); return Value; } EXPORT_API void* FirstNodePtr(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument); if (!InDocument) { return NULL; } if (InNodePtr != NULL) { return InNodePtr->first_node(); } else { RapidXmlNative* Native = (RapidXmlNative*)InDocument; rapidxml::xml_document<>* Document = Native->GetDocument(); assert(Document); return Document->first_node(); } } EXPORT_API void* FirstNodePtrWithName(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument); if (!InDocument) { return NULL; } if (InNodePtr != NULL) { return InNodePtr->first_node(pName); } else { RapidXmlNative* Native = (RapidXmlNative*)InDocument; rapidxml::xml_document<>* Document = Native->GetDocument(); assert(Document); return Document->first_node(pName); } } EXPORT_API void* NextSiblingPtr(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument && InNodePtr); if (!InDocument || !InNodePtr) { return NULL; } return InNodePtr->next_sibling(); } EXPORT_API void* NextSiblingPtrWithName(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr, const char* pName) { assert(InDocument && InNodePtr); if (!InDocument || !InNodePtr) { return NULL; } return InNodePtr->next_sibling(pName); } EXPORT_API void* GetNodeTagPtr(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument && InNodePtr); if (!InDocument || !InNodePtr) { return NULL; } return InNodePtr->name(); } EXPORT_API int GetChildNodeCount(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument && InNodePtr); if (!InDocument || !InNodePtr) { return NULL; } rapidxml::xml_node<>* Child = InNodePtr->first_node(); int Result = 0; while (Child) { ++Result; Child = Child->next_sibling(); } return Result; } EXPORT_API int GetAttributeCount(RapidXmlNative* InDocument, rapidxml::xml_node<>* InNodePtr) { assert(InDocument && InNodePtr); if (!InDocument || !InNodePtr) { return NULL; } rapidxml::xml_attribute<>* Attr = InNodePtr->first_attribute(); int Result = 0; while (Attr) { ++Result; Attr = Attr->next_attribute(); } return Result; } EXPORT_API void* GetAttributeNamePtr(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); return InAttrPtr->name(); } EXPORT_API void* GetAttributeValuePtr(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); return InAttrPtr->value(); } EXPORT_API bool GetAttributeValueBool(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return false; } #ifdef _MSC_VER return _stricmp(InAttrPtr->value(), "true") == 0; #else return strcasecmp(InAttrPtr->value(), "true") == 0; #endif } EXPORT_API int GetAttributeValueInt(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return atoi(InAttrPtr->value()); } EXPORT_API unsigned GetAttributeValueUInt(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return strtoul(InAttrPtr->value(), NULL, 10); } EXPORT_API long long GetAttributeValueInt64(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return atoll(InAttrPtr->value()); } EXPORT_API unsigned long long GetAttributeValueUInt64(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return strtoull(InAttrPtr->value(), NULL, 10); } EXPORT_API float GetAttributeValueFloat(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return (float)atof(InAttrPtr->value()); } EXPORT_API double GetAttributeValueDouble(RapidXmlNative* InDocument, rapidxml::xml_attribute<>* InAttrPtr) { assert(InDocument && InAttrPtr && InAttrPtr->document() == InDocument->GetDocument()); if (!InAttrPtr->value()) { return 0; } return atof(InAttrPtr->value()); } }

 

    github上的readme.md,英語很垃圾,請見諒:

# UnityRapidXml
this is a simple wrapper for rapidxml(http://rapidxml.sourceforge.net/) for C#.
it is the fastest xml parser in C#, i crate this library because the default xml parser in c# is too swollen and slow. in Unity Engine, there is a Mono.xml you can use. but is also slow. this library is implemented in native, and easy use in c#. you can clone or download this project to see the detail. i have test it on windows,android and ios. you can use it for your unity game. tutorial: please install visiual studio 2015 and mobile developer kit, and then you can open the solution file directly. or you can create the project by yourself. all of the codes are under the directory RapidXml, all export functions in Source/RapidXml.cpp you can build this cpp file to dll for windows, copy the dll to Assets/Plugins/X86 build android so file, copy to Assets/Plugins/Android. build bundle for macosx, copy to Assets/Plugins ios: copy code files to your xcode project if you use il2cpp, you can use XUPorter to do this. bodong Email: bodong@tencent.com

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM