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
Unity引擎下最快的Xml读取器:UnityRapidXml的更多相关文章
- {"读取 XML 数据时,超出最大名称表字符计数配额(16384)。。。。通过更改在创建 XML 读取器时所使用的 XmlDictionaryReaderQuotas 对象的 MaxNameTableCharCount 属性,。。
这个问题倒腾了快一周,看了网上各种解决方案,还看了用谷歌翻译看了全英文的,参照了修改也没能够解决问题. 最后只有自己一行一行断点,一行一行删除代码,各种检测.主要是我在webservice里面新添加几 ...
- 盛大游戏技术总监徐峥:Unity引擎使用的三种方式
在5月13日Unite 2017 案例分享专场上,盛大游戏技术总监徐峥分享了使用Unity引擎的三种方式,以下为详细内容: 大家好,我先简单介绍一下我自己,我是盛大游戏的技术总监徐峥.我今天想分享的主 ...
- 从Unity引擎过度到Unreal4引擎(最终版)
原文地址:http://demo.netfoucs.com/u011707076/article/details/44036839 前言 寒假回家到现在已经有十多天了,这些天回家不是睡就是吃....哎 ...
- Linq to XML 读取XML 备忘笔记
本文转载:http://www.cnblogs.com/infozero/archive/2010/07/13/1776383.html Linq to XML 读取XML 备忘笔记 最近一个项目中有 ...
- 【BUG】xml读取异常Invalid byte 1 of 1-byte UTF-8 sequence
来自http://blog.csdn.net/chenyanbo/article/details/6866941 xml读取异常Invalid byte 1 of 1-byte UTF-8 seque ...
- C#使用Linq To XML读取XML,Linq生成XML,Linq创建带属性或带节点XML
using System; using System.Linq; using System.Xml.Linq; namespace Sample2 { class Program { static v ...
- XML序列化器读取XML数据
PS:标题我还真的不知道该怎么取比较好,大家将就下吧^_^ 场景:上周接到一个任务,要求我把ASP写的会员充值功能,用ASP.NET复制一遍,没有给我需求文档,就是让我根据代码去分析业务逻辑,然后看到 ...
- Unite 2017 | Unity引擎发展四大方向
Unite 2017 Shanghai已落幕,今天为大家分享本次大会备受关注的Keynote主题演讲.本次大会Keynote主题演讲聚焦了Unity全球领导团队,包括Unity创始人David Hel ...
- Mysql InnoDB引擎下 事务的隔离级别
mysql InnoDB 引擎下事物学习 建表user CREATE TABLE `user` ( `uid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, ...
随机推荐
- ThinkphpCMF笔记
1.模板js,css文件__PUBLIC__ <link href="__TMPL__Public/style.css" rel="stylesheet" ...
- Oracle数据库找回密码
Oracle数据库忘记用户的密码.经验证,可行的解决方案如下: 1.Ctrl + R 打开cmd窗口,输入 sqlplus / as sysdba (注意/左右两侧有空格) 2.运行cmd ,输入 ...
- 总是多次出现 那个同样的 权限错误 _storage_write_error_, 所以一开始就把机器设好setenforce 0
把根目录下的所有文件/目录, 都设为权限777. 好像没有必要把所有的东西, 都设为777, 实际上问题是由selinux引起的, 所以, 只要把相应的目录, 不一定是所有的目录, 只是要写入内容的目 ...
- JQuery radio(单选按钮)操作方法汇总
这篇文章主要介绍了JQuery radio(单选按钮)操作方法汇总,本文讲解了获取选中值.设置选中值.根据Value值设置选中.删除Radio.遍历等内容,需要的朋友可以参考下 随着Jquery的 ...
- Java 中文乱码问题总结
开发java应用出现乱码是很常见的,毕竟现在unicode的使用还不是很广泛,在使用gb2312(包含了gbk简体,big5繁体)的系统中要正确 实现中文的display和数据库的存储是最基本的要求. ...
- 在sql语句中使用 xml for path 格式化字符串的方法总结
此方法实现的是将查询表中的某个字段,格式化成 字符串1,字符串2,字符串3...的格式 假设我们现在有两个表 分别是 分组表 grouped和分组成员表 groupuser grouped表有连个字 ...
- linux 下C++查询mysql数据库
上一节我们看了怎么使用mysql提供的API来连接mysql数据库,现在来看看怎么执行一条简单的查询语句,并且把查询的结果显示出来. 准备工作:首先新建了一个数据库inote,在这个数据库下面新建了一 ...
- C# 调用webservice 几种办法(转载)
原文地址: http://www.cnblogs.com/eagle1986/archive/2012/09/03/2669699.html //=========================== ...
- MVC中使用Entity Framework 基于方法的查询学习笔记 (三)
紧接上文,我们已经学习了MVC数据上下文中两个常用的类,这两个类承载着利用函数方式进行数据查询的全部内容,我们既然已经了解了DbSet<TEntity> 是一个泛型集合,并且实现了一些接口 ...
- ffmpeg-20160929-bin.7z
ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 5 屏幕横向放大 20 像素 6 屏幕横向缩小 20 像素 S 下一帧 [ -2秒 ] +2 ...