This commit is contained in:
2025-05-13 02:46:21 +03:00
parent 143e16692e
commit 86914b7fcc
610 changed files with 92343 additions and 2 deletions
+118
View File
@@ -0,0 +1,118 @@
#ifndef AnimationController_h__
#define AnimationController_h__
#include <map>
#include <vector>
#include "AnimationTrack.h"
#include "Skeleton.h"
#include "LString.h"
namespace LifeGraphics
{
class AnimationController
{
public:
float fadeSpeed;
std::map<String, AnimationTrack*> tracks;
int trackCount;
Skeleton* skeleton;
int lastId;
std::vector<AnimationTrack*> plainList;
void CrossFade(String name)
{
AnimationTrack* t = tracks[name];
t->Weight += fadeSpeed;
if (t->Weight > 1.0f) t->Weight = 1.0f;
for(std::map<String, AnimationTrack*>::iterator it = tracks.begin(); it != tracks.end(); it++)
{
AnimationTrack* t2 = it->second;
if (t2->Layer == t->Layer && t2->Name != t->Name)
{
t2->Weight -= fadeSpeed;
if (t2->Weight < 0) t2->Weight = 0;
}
}
}
AnimationController()
:fadeSpeed(1.0f/20.0f), trackCount(0),lastId(0)
{
}
void SetState(const String& stateName)
{
}
/// <summary>
/// Add animatrion track to the current animation controller.
/// </summary>
/// <param name="track">Animation track to add.</param>
void AddTrack(AnimationTrack* track)
{
track->ID = lastId++;
tracks[track->Name] = track;
trackCount++;
}
void SetTrackWeight(String track, float weight)
{
tracks[track]->Weight = weight;
}
void LerpTransform(BoneTransform* left, const BoneTransform* right, float amount, BoneTransform* result)
{
if (amount == 0)
{
result->Rotation = left->Rotation;
result->Translation = left->Translation;
result->boneId = left->boneId;
return;
}
else if (amount == 1.0f)
{
result->Rotation = right->Rotation;
result->Translation = right->Translation;
result->boneId = right->boneId;
return;
}
QuatLerp(left->Rotation, right->Rotation, amount, result->Rotation);
Vec3Lerp(left->Translation, right->Translation, amount, result->Translation);
result->boneId = left->boneId;
}
void AdvanceTime(float dt)
{
for(std::map<String, AnimationTrack*>::iterator it = tracks.begin(); it != tracks.end(); it++)
{
AnimationTrack* track = it->second;
track->AdvanceTime(dt);
const BoneTransform* transform = track->GetTransform();
for (int i = 0; i < skeleton->BonesCount; i++)
{
for (int j = 0; j < track->Frames[0].boneCount; j++)
{
if (transform[j].boneId == i)
{
Bone* bone = skeleton->GetBone(i);
BoneTransform lt = bone->LocalTransform;
LerpTransform(&lt, &transform[j], track->Weight, &bone->LocalTransform);
}
}
}
}
skeleton->UpdateTransform();
}
/// <summary>
/// Use to set up mesh into initial pose
/// </summary>
void Reset()
{
tracks[0]->Reset();
}
};
}
#endif // AnimationController_h__
+39
View File
@@ -0,0 +1,39 @@
#ifndef AnimationFrame_h__
#define AnimationFrame_h__
#include <vector>
#include "BoneTransform.h"
namespace LifeGraphics
{
struct AnimationFrame
{
int name;
float time;
int boneCount;
std::vector<BoneTransform> bonesTransformations;
AnimationFrame()
{
}
void getTransformations(BoneTransform* transform)
{
for(int i = 0; i < boneCount; i++)
transform[i] = bonesTransformations[i];
}
BoneTransform getTransform(int id)
{
return bonesTransformations[id];
}
void addBoneTransform(BoneTransform& tr)
{
bonesTransformations.push_back(tr);
boneCount++;
}
AnimationFrame(float frameTime)
:boneCount(0)
{
time = frameTime;
name = -1;
}
};
}
#endif // AnimationFrame_h__
+165
View File
@@ -0,0 +1,165 @@
#ifndef AnimationTrack_h__
#define AnimationTrack_h__
#include "AnimationFrame.h"
#include "LString.h"
#include "math/LifeMath.h"
namespace LifeGraphics
{
class AnimationTrack
{
public:
String Name;
int Layer;
AnimationFrame* Frames;
BoneTransform* transformations;
int FramesCount;
int ID;
int prev;
float Weight;
bool Enabled;
float TrackTime;
bool Loop;
float TrackPosition;
bool Playing;
AnimationTrack(int framesCount)
:Layer(0), ID(0), Weight(1.0f),TrackPosition(0.0f), prev(0)
{
Frames = new AnimationFrame[framesCount];
transformations = new BoneTransform[framesCount];
FramesCount = framesCount;
}
~AnimationTrack()
{
if(Frames)
delete[] Frames;
if(transformations)
delete[] transformations;
}
void setFrame(AnimationFrame& frame, int id)
{
Frames[id] = frame;
}
const BoneTransform* GetTransform()
{
/*if (TrackPosition > Frames[FramesCount - 1].time)
if (Loop)
TrackPosition = 0.0f;
else
TrackPosition = Frames[FramesCount - 1].time;*/
//if(TrackPosition < 0.0f || TrackPosition > Frames[FramesCount - 1].time)
//printf("OMFGNAH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
for (int i = 0; i < FramesCount; i++)
{
if (Frames[i].time == TrackPosition)
{
Frames[i].getTransformations(transformations);
return transformations;
}
int next = i + 1;
if(next >= FramesCount)
next = 0;
if (TrackPosition > Frames[i].time && TrackPosition < Frames[next].time)
{
float amount = (TrackPosition - Frames[i].time) / (Frames[next].time - Frames[i].time);
InterpolateFrames(Frames + i, Frames + (next), amount);
return transformations;
}
}
return transformations;
}
void InterpolateFrames(AnimationFrame* start, AnimationFrame* end, float amount)
{
for (int i = 0; i < start->boneCount; i++)
{
BoneTransform newTransform;
//BoneTransform tr1 = start->getTransform(i);
BoneTransform tr2 = end->getTransform(i);
/* QuatSLerp(tr1.Rotation, tr2.Rotation, amount, newTransform.Rotation);
Vec3Lerp(tr1.Translation, tr2.Translation, amount, newTransform.Translation);
if(amount < 0.0f | amount > 1.0f)
{
printf("PIZDEC!");
}
printf("Select frame: %i, Frame time: %f\n", end->name, end->time);
*/
newTransform.boneId = tr2.boneId;
newTransform.Translation = tr2.Translation;
newTransform.Rotation = tr2.Rotation;
transformations[i] = newTransform;
}
}
void AdvanceTime(float dt)
{
if (Playing && Weight >0)
{
TrackPosition += dt;
// TrackPosition = Frames[1].time;
//printf("Frame one id: %i\n", Frames[1].name);
if (TrackPosition > Frames[FramesCount - 1].time)
{
if (Loop)
{
//DoEvents(prevPos, TrackTime);
TrackPosition = TrackPosition - Frames[FramesCount - 1].time;
//OnTrackEnd();
//OnTrackStart();
//
}
else
{
TrackPosition = TrackTime;
//OnTrackEnd();
Playing = false;
}
}
if (TrackPosition < 0)
{
TrackPosition = 0;
// OnTrackStart();
}
if (TrackPosition == 0)
{
//OnTrackStart();
}
else
{
//DoEvents(prevPos, TrackPosition);
}
}
}
void Stop()
{
Playing = false;
}
void Play()
{
if (TrackPosition >= TrackTime)
TrackPosition = 0;
Playing = true;
}
void Reset()
{
TrackPosition = 0;
}
};
}
#endif // AnimationTrack_h__
+47
View File
@@ -0,0 +1,47 @@
#ifndef Bone_h__
#define Bone_h__
#include <map>
#include <vector>
#include "BoneTransform.h"
#include <LString.h>
namespace LifeGraphics
{
class Bone
{
public:
BoneTransform BaseTransform;
BoneTransform LocalTransform;
BoneTransform InitialTransform;
//public BoneTransform AbsoluteTransform = new BoneTransform();
int ID;
Bone* Parent;
std::vector<Bone*> Childs;
String BoneName;
LifeMath::float4x4 TransformMatrix;
LifeMath::float4x4 AbsoluteMatrix;
int ParentId;
void AddChild(Bone* child)
{
Childs.push_back(child);
}
void clearChilds()
{
Childs.clear();
}
void Update()
{
}
Bone(int id, const String& name, int parentId)
:ID(-1), Parent(0)
{
BoneName = name;
ID = id;
ParentId = parentId;
}
};
}
#endif // Bone_h__
+65
View File
@@ -0,0 +1,65 @@
#ifndef BoneTransform_h__
#define BoneTransform_h__
#include "math/LifeMath.h"
namespace LifeGraphics
{
struct BoneTransform
{
public:
int boneId;
LifeMath::float3 Translation;
LifeMath::Quaternion Rotation;
BoneTransform()
:boneId(0)
{
}
BoneTransform operator =(const BoneTransform& right)
{
boneId = right.boneId;
Translation = right.Translation;
Rotation = right.Rotation;
return *this;
}
BoneTransform operator *(const BoneTransform& right)
{
BoneTransform bt;
bt.Translation = Translation + right.Translation;
bt.Rotation = Rotation * right.Rotation;
return bt;
}
LifeMath::float4x4 GetMatrix()
{
LifeMath::float4x4 rot;
LifeMath::float4x4 trans;
LifeMath::Mat4x4RotationQuaternion(Rotation, rot);
LifeMath::Mat4x4Translation(Translation, trans);
return rot*trans;
}
LifeMath::float4x4 GetMatrixInvert()
{
LifeMath::float4x4 rot;
LifeMath::float4x4 trans;
LifeMath::Mat4x4RotationQuaternion(Rotation, rot);
LifeMath::Mat4x4Translation(Translation, trans);
LifeMath::float4x4 transform = rot * trans;
transform = LifeMath::Mat4x4Invert(&transform);
return transform;
}
BoneTransform GetInverted()
{
BoneTransform tr;
tr.Translation = -this->Translation;
tr.Rotation = this->Rotation;
QuatInvert(tr.Rotation);
return tr;
}
};
}
#endif // BoneTransform_h__
+19
View File
@@ -0,0 +1,19 @@
#ifndef BoundingSphere_h__
#define BoundingSphere_h__
#include "math/LifeMath.h"
namespace LifeGraphics
{
class BoundingSphere
{
public:
BoundingSphere()
:center(0.0f, 0.0f, 0.0f), radius(20.0f)
{
}
~BoundingSphere(){}
float radius;
LifeMath::float3 center;
};
}
#endif // BoundingSphere_h__
+24
View File
@@ -0,0 +1,24 @@
#include "CG.h"
namespace LifeGraphics
{
IRenderer* CG::GetRenderer()
{
return g_Renderer;
}
void CG::SetRenderer(IRenderer* renderer)
{
g_Renderer = renderer;
}
CG::CG()
:g_Renderer(0)
{
}
CG::~CG()
{
g_Renderer = NULL;
}
void CG::initialize()
{
}
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef CG_H__
#define CG_H__
#include "render/IRenderer.h"
#include "Singleton.h"
namespace LifeGraphics
{
class CG;
class CG : public Singleton<CG>
{
private:
IRenderer* g_Renderer;
public:
CG();
~CG();
void initialize();
void SetRenderer(IRenderer* renderer);
IRenderer* GetRenderer();
};
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#include "camera/Camera.h"
//////////////////////////////////////////////////////////////////////////
namespace LifeGraphics
{
Camera::Camera()
{
freeCam = true;
isViewValid = false;
isProjValid = false;
fDir = LifeMath::float3(0, 0, -1);
fov = 3.1415926535f / 4.0f;
nearPlane = 0.1f;
farPlane = 400.0f;
viewAspect = 1.0f;
eye = LifeMath::float3(0, 0, 0);
up = LifeMath::float3(0, 1, 0);
at = LifeMath::float3(0, 0, 1);
right = LifeMath::float3(1, 0, 0);
Mat4x4LookAtLH(eye, at, up, viewMatrix);
Mat4x4PerspectiveFOV(fov, viewAspect, nearPlane, farPlane, projectionMatrix);
frustum = Frustum(viewMatrix * projectionMatrix);
}
Camera::~Camera()
{
}
}
+45
View File
@@ -0,0 +1,45 @@
#include "CustomSwapChain.h"
namespace LifeGraphics
{
CustomSwapChain::CustomSwapChain(uint16 width, uint16 height, uint16 buffer_cnt, LifeGraphics::IRenderer* host, IDataFormat format)
:back_buffer(nullptr), depth_buffer(nullptr){
if(!host){
sc_width = sc_height = sc_buffers = 0;
return;
}
sc_width = width;
sc_height = height;
sc_buffers = buffer_cnt;
sc_format = format;
sc_renderer = host;
RebuildBuffers();
}
LifeGraphics::ITexture2D* CustomSwapChain::GetBackBuffer(uint8 id){
return back_buffer;
}
LifeGraphics::ITexture2D* CustomSwapChain::GetDepthBuffer(uint8 id){
return depth_buffer;
}
void CustomSwapChain::Resize(uint16 width, uint16 height){
if(width != sc_width || height != sc_height){
sc_width = width;
sc_height = height;
RebuildBuffers();
Event_Resized.Invoke(this);
}
}
void CustomSwapChain::Present(){
Event_Presented.Invoke(this);
}
void CustomSwapChain::RebuildBuffers(){
if(back_buffer)
back_buffer->Release();
if(depth_buffer)
depth_buffer->Release();
back_buffer = sc_renderer->CreateRenderTarget(sc_width, sc_height, sc_format);
depth_buffer = sc_renderer->CreateDepthTarget(sc_width, sc_height, FORMAT_D24_UNORM_S8_UINT);
}
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef CustomSwapChain_h__
#define CustomSwapChain_h__
#include "ISwapChain.h"
#include "render/IRenderer.h"
namespace LifeGraphics
{
class CustomSwapChain : public ISwapChain
{
public:
CustomSwapChain(uint16 width, uint16 height, uint16 buffer_cnt, LifeGraphics::IRenderer* host, IDataFormat format);
LifeGraphics::ITexture2D* GetBackBuffer(uint8 id);
LifeGraphics::ITexture2D* GetDepthBuffer(uint8 id);
void Resize(uint16 width, uint16 height);
void Present();
private:
void RebuildBuffers();
uint16 sc_width;
uint16 sc_height;
uint16 sc_buffers;
IDataFormat sc_format;
LifeGraphics::IRenderer* sc_renderer;
LifeGraphics::ITexture2D* back_buffer;
LifeGraphics::ITexture2D* depth_buffer;
};
}
#endif // CustomSwapChain_h__
+137
View File
@@ -0,0 +1,137 @@
#ifndef DayTime_h__
#define DayTime_h__
class DayTime
{
public:
static const int MaxSeconds = 24 * 3600;
int Hours, Minutes, Seconds;
DayTime(int hours, int minutes, int seconds)
{
Hours = hours;
Minutes = minutes;
Seconds = seconds;
}
DayTime()
{
Hours = 0;
Minutes = 0;
Seconds = 0;
}
DayTime(int time)
{
int dc1 = time % 3600;
int dc2 = dc1 % 60;
Hours = ((time - dc1) / 3600) % 24;
Minutes = (dc1 - dc2) / 60;
Seconds = dc2;
}
int ToSeconds() const
{
return Hours * 3600 + Minutes * 60 + Seconds;
}
bool operator >=(const DayTime& right) const
{
return ToSeconds() >= right.ToSeconds();
}
bool operator <=(const DayTime& right) const
{
return ToSeconds() <= right.ToSeconds();
}
bool operator >(const DayTime& right) const
{
return ToSeconds() > right.ToSeconds();
}
bool operator <(const DayTime& right) const
{
return ToSeconds() < right.ToSeconds();
}
bool operator !=(const DayTime& right) const
{
return ToSeconds() != right.ToSeconds();
}
bool operator ==(const DayTime& right) const
{
return ToSeconds() == right.ToSeconds();
}
DayTime operator +(const DayTime& right) const
{
int sum = ToSeconds() + right.ToSeconds();
return DayTime(sum);
}
DayTime operator +(int time) const
{
int sum = ToSeconds() + time;
return DayTime(sum);
}
DayTime operator -(const DayTime& right) const
{
int t1 = ToSeconds();
int t2 = right.ToSeconds();
int s = 0;
if (t1 < t2)
{
s = MaxSeconds - t2 + t1;
}
else
s = t1 - t2;
return DayTime(s);
}
DayTime operator -(int time)
{
int t1 = ToSeconds();
int t2 = time;
int s = 0;
if (t1 < t2)
{
s = MaxSeconds - t2 + t1;
}
else
s = t1 - t2;
return DayTime(s);
}
DayTime operator /(int divider) const
{
return DayTime(ToSeconds() / divider);
}
DayTime operator /(const DayTime& divider) const
{
return DayTime(ToSeconds() / divider.ToSeconds());
}
void Add(const DayTime& time)
{
SetTime(ToSeconds() + time.ToSeconds());
}
void Add(int time)
{
SetTime(ToSeconds() + time);
}
void SetTime(int time)
{
int dc1 = time % 3600;
int dc2 = dc1 % 60;
Hours = ((time - dc1) / 3600) % 24;
Minutes = (dc1 - dc2) / 60;
Seconds = dc2;
}
};
#endif // DayTime_h__
+20
View File
@@ -0,0 +1,20 @@
#ifndef GEOMETRY_SUBSET_H__
#define GEOMETRY_SUBSET_H__
#include <vector>
namespace LifeGraphics
{
class GeometrySubset
{
public:
BOOL HasBones;
int Length;
int Offset;
int FaceCount;
int BonesCount;
std::vector<int> MatrixList;
};
}
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef GLOBALS_H__
#define GLOBALS_H__
#include "CG.h"
#include "ResourceManager.h"
#include "Types.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if (p) { for(int lll=0; lll<100;lll++)(p)->Release(); (p)=NULL; } }
#endif
enum ParticleBlendType
{
ParticleBlendType_AlphaBased,
ParticleBlendType_ColorBased,
ParticleBlendType_Additive,
ParticleBlendType_None
};
enum EParticleFlags
{
PART_FLAG_BILLBOARD = 0, // Usual particle
PART_FLAG_HORIZONTAL = 1, // Flat horisontal rounds on the water
PART_FLAG_UNDERWATER = 2, // Particle will be removed if go out from outdoor water
PART_FLAG_LINEPARTICLE = 4, // Draw billboarded line from vPosition to vPosition+vDirection
PART_FLAG_SWAP_XY = 8, // Alternative order of rotation (zxy)
PART_FLAG_SIZE_LINEAR = 16, // Change size liner with time
PART_FLAG_NO_OFFSET = 32, // Disable centering of static objects
PART_FLAG_DRAW_NEAR = 64, // Render particle in near space (weapon)
PART_FLAG_FOCUS_PLANE = 128, // Focus will spread partices along normal plane instead of direction axis.
PART_FLAG_NO_DRAW_UNDERWATER = 256, // Particle will be not visible when it position is under water
PART_FLAG_RIGIDBODY = 512, // If bRealPhysics set to true, physicalizing particles as rigid bodies
PART_FLAG_SPACELOOP = 1024, // Lock paticles in box around emitter position, use ParticleParams::vSpaceLoopBoxSize to set box size
PART_FLAG_SPACELIMIT = 2048, // Limit paticles by box around emitter position, use ParticleParams::vSpaceLoopBoxSize to set box size
PART_FLAG_SPEED_IN_GRAVITY_DIRECTION = 4096, // Ignores normal passed to particle effect and always uses gravity direction for initial speed direction.
PART_FLAG_BIND_POSITION_TO_EMITTER = 0x2000, // Always keep particle position binded to position of the emitter (for rockets etc...)
PART_FLAG_BIND_EMITTER_TO_CAMERA = 0x4000, // Attach emitter to camera pos
PART_FLAG_NO_INDOOR = 0x8000, // Kill particle if it enters indoor
};
enum QUALITY
{
Q_HIGH = 0,
Q_MED = 1,
Q_LOW = 2
};
#endif
+102
View File
@@ -0,0 +1,102 @@
#ifndef IGraphicsNode_h__
#define IGraphicsNode_h__
#include "math/LifeMath.h"
#include <vector>
#include <BoundingBox3D.h>
#include "BoundingSphere.h"
#include <ITransform.h>
#include "LString.h"
namespace LifeGraphics
{
enum NodeType
{
NT_CAMERA, NT_LIGHT, NT_MESH, NT_PARTICLE_SYSTEM, NT_TERRAIN, NT_SCENE_ROOT
};
class IGraphicsNode
{
protected:
LifeCore::ITransform* defaultTransform;
LifeCore::ITransform* transform;
private:
public:
long Id;
String Name;
std::vector<IGraphicsNode*> childs;
IGraphicsNode* parent;
bool castShadows;
LifeCore::BoundingBox3D bBox;
BoundingSphere bSphere;
LifeMath::float3 transformedBox[8];
const LifeCore::BoundingBox3D* getBoundingBox()
{
return &bBox;
}
const LifeMath::float3* getTransformedBox()
{
//if(!transform->IsValid())
//{
bBox.GetCorners(transformedBox);
LifeMath::float4x4 mTransform = transform->GetMatrix();
for(int i = 0; i<8; i++)
{
transformedBox[i] = Vec3TransformCoordinate( mTransform, transformedBox[i]);
}
//}
return transformedBox;
}
const BoundingSphere* getBoundingSphere()
{
return &bSphere;
}
LifeCore::ITransform* getTransform()
{
return transform;
}
void SetTransform(LifeCore::ITransform* _transform)
{
transform = _transform;
}
void setParent(IGraphicsNode* node)
{
parent = node;
}
IGraphicsNode* getParent()
{
return parent;
}
IGraphicsNode()
:castShadows(true)
{
defaultTransform = new LifeCore::ITransform();
transform = defaultTransform;
}
virtual ~IGraphicsNode()
{
if(defaultTransform)
{
delete defaultTransform;
defaultTransform = NULL;
}
transform = NULL;
}
void addChild(IGraphicsNode* node)
{
childs.push_back(node);
node->setParent(this);
}
virtual NodeType getType() = 0;
virtual void update(float timeElapsed) = 0;
};
}
#endif // ISceneNode_h__
+88
View File
@@ -0,0 +1,88 @@
#ifndef IMesh_h__
#define IMesh_h__
#include "IGraphicsNode.h"
#include "render/IVertexBuffer.h"
#include "render/IIndexBuffer.h"
//#include "render/IMaterial.h"
#include "render/IInputLayout.h"
#include "SkinInfo.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
#endif
namespace LifeGraphics
{
class GeometrySubset
{
public:
GeometrySubset()
{
MatrixList = (int*)0;
}
~GeometrySubset()
{
//SAFE_DELETE_ARRAY(MatrixList);
}
int HasBones;
int Length;
int Offset, FaceCount, BonesCount;
int* MatrixList;
int matrixCount;
//IMaterial material;
//public LifeMaterial Material;
};
class IMesh
{
public:
int Id;
LifeCore::BoundingBox3D bBox;
LifeMath::float3 transformedBox[8];
String Name;
IMesh(IVertexBuffer* _vertexData, IIndexBuffer* _indexData, GeometrySubset* _subsets, IInputLayout* _layout, int isSkinned, const LifeCore::BoundingBox3D& box, const String& name)
{
Name = name;
IsSkinned = isSkinned;
Id = 0;
vertexData = _vertexData;
indexData = _indexData;
subsets = _subsets;
inputLayout = _layout;
bBox = box;
bBox.GetCorners(transformedBox);
/*
if(subsetCount == 2)
subsetCount = 1;*/
}
virtual ~IMesh()
{
SAFE_DELETE(vertexData);
SAFE_DELETE(indexData);
SAFE_DELETE_ARRAY(subsets);
SAFE_DELETE(inputLayout);
}
NodeType getType()
{
return NT_MESH;
}
int subsetCount;
public:
IVertexBuffer* vertexData;
IIndexBuffer* indexData;
GeometrySubset* subsets;
IInputLayout* inputLayout;
SkinInfo skin;
int IsSkinned;
};
}
#endif // IMesh_h__
+87
View File
@@ -0,0 +1,87 @@
#ifndef IOBJECT_H__
#define IOBJECT_H__
#include "LString.h"
#include "render/IMaterialProxy.h"
#include "Globals.h"
#include "math/LifeMath.h"
#include "IGraphicsNode.h"
#include "camera/Camera.h"
namespace LifeGraphics
{
struct PER_OBJECT_CONSTANTS
{
LifeMath::float4x4 mWorld;
};
class Submesh
{
public:
String name;
int offset;
int length;
};
class IObject : public IGraphicsNode
{
protected:
IMaterialProxy** materials;
Submesh* subsets;
IConstantBuffer* perObjectCb;
IConstantBuffer* materialCb;
public:
IObject()
{
perObjectCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_OBJECT_CONSTANTS));
}
virtual ~IObject(){}
virtual void bind() = 0;
virtual int getSumbeshCount() const = 0;
virtual void setMaterial(IMaterial* mat, int submesh, bool genShaders) = 0;
Submesh* getSubmesh(int id)
{
return subsets + id;
}
const IMaterialProxy* getMaterial(int submesh) const
{
return materials[submesh];
}
IMaterialProxy* getMaterial(int submesh)
{
return materials[submesh];
}
/*const IMaterial* getMaterial(String submesh) const
{
int count = getSumbeshCount();
for(int i = 0; i < count; i++)
{
if(*getSubmeshName(i) == submesh)
return materials + i;
}
return NULL;
}
IMaterial* getMaterial(String submesh)
{
int count = getSumbeshCount();
for(int i = 0; i < count; i++)
{
if(*getSubmeshName(i) == submesh)
return materials + i;
}
return NULL;
}*/
//virtual const String* getSubmeshName(int submesh) const = 0;
//virtual const LifeMath::float3intersect(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir) const = 0;
//virtual const LifeMath::float3intersectSubmesh(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir, int submesh) const = 0;
//virtual const LifeMath::float3intersectSubmesh(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir, const String& submesh) const = 0;
virtual void selectLod(int lodNum) = 0;
virtual void selectLod(const Camera* cam) = 0;
virtual void render(int submesh) = 0;
//virtual int getVertexCount(int submesh) = 0;
//virtual int getFaceCount(int submesh) = 0;
};
}
#endif
+184
View File
@@ -0,0 +1,184 @@
#ifndef IObjectMesh_h__
#define IObjectMesh_h__
#include "IObject.h"
#include "LString.h"
#include "Globals.h"
#include "render/IMaterial.h"
#include <vector>
namespace LifeGraphics
{
#define MAX_BONES_COUNT 128
static const int PerObjectSkinningVSDataSize = 4 * 4 * 4 * MAX_BONES_COUNT;
struct PerObjectSkinningVSData
{
LifeMath::float4x4* mWorld;
};
struct MeshLOD
{
IMesh* mesh;
float distance;
};
class IObjectMesh : public IObject
{
private:
std::vector<MeshLOD> lods;
IMesh* mesh;
IConstantBuffer* skinBuffer;
LifeMath::float4x4* skinTempBuffer;
public:
IObjectMesh(IMesh* mesh)
{
setLod(mesh, 0.0f);
selectLod(0);
materials = new IMaterialProxy*[mesh->subsetCount];
memset(materials, 0, mesh->subsetCount * sizeof(materials[0]));
//HACK
for(int i = 0; i < mesh->subsetCount; i++)
{
materials[i] = ResourceManager::me()->getDefaultMaterial()->CreateProxy(this);
}
if(mesh->IsSkinned)
{
skinBuffer = CG::me()->GetRenderer()->CreateConstantBuffer(PerObjectSkinningVSDataSize);
skinTempBuffer = new LifeMath::float4x4[MAX_BONES_COUNT];
AnimationTrack* track = ResourceManager::me()->LoadAnimatrionTrack(AS_STRING("root/Data/Animations/miranda.sat"));
mesh->skin.controller.AddTrack(track);
}
}
IObjectMesh(String path)
{
IMesh* mesh = ResourceManager::me()->GetMesh(path);
setLod(mesh, 0.0f);
selectLod(0);
materials = new IMaterialProxy*[mesh->subsetCount];
memset(materials, 0, mesh->subsetCount * sizeof(materials[0]));
//HACK
for(int i = 0; i < mesh->subsetCount; i++)
{
materials[i] = ResourceManager::me()->getDefaultMaterial()->CreateProxy(this);
}
if(mesh->IsSkinned)
{
skinBuffer = CG::me()->GetRenderer()->CreateConstantBuffer(PerObjectSkinningVSDataSize);
skinTempBuffer = new LifeMath::float4x4[MAX_BONES_COUNT];
AnimationTrack* track = ResourceManager::me()->LoadAnimatrionTrack(AS_STRING("root/Data/Animations/miranda.sat"));
mesh->skin.controller.AddTrack(track);
}
}
~IObjectMesh()
{
}
void setMaterial(IMaterial* mat, int submesh, bool genShaders)
{
materials[submesh] = mat->CreateProxy(this);
//NEED FIXUP SHADERS
/*EFFECT_FLAGS flags = EF_NONE;
if(mesh->IsSkinned)
{
flags = EF_SKINNING;
}
*/
// materials[submesh]->pixelShader = ResourceManager::me()->getShader(materials[submesh],flags, ST_PS);
// materials[submesh]->vertexShader = ResourceManager::me()->getShader(materials[submesh],flags, ST_VS);
// materials[submesh]->vertexShaderLinearDepth = ResourceManager::me()->getShader(materials[submesh],flags | EF_LINEAR_DEPTH, ST_VS);
if(genShaders)
{
//materials[submesh]->g_buffer_pass_ps = ResourceManager::me()->getShader(materials[submesh],flags | EF_G_BUFFER_PREPASS, ST_PS);
//materials[submesh]->g_buffer_pass_vs = ResourceManager::me()->getShader(materials[submesh],flags | EF_G_BUFFER_PREPASS, ST_VS);
}
}
void update(float dt)
{
PER_OBJECT_CONSTANTS objConst;
objConst.mWorld = getTransform()->GetMatrix();
perObjectCb->Update(&objConst, sizeof(PER_OBJECT_CONSTANTS));
for(int i = 0; i< getSumbeshCount(); i++)
{
IMaterialProxy* mat = getMaterial(i);
/////////*if(mat->diffuseMap.ptr() && mat->diffuseMap->IsVideoTexture())
////////{
//////// IVideoTexture* tex = static_cast<IVideoTexture*>(mat->diffuseMap.ptr());
//////// tex->Update(dt);
////////}*/
}
if (mesh->IsSkinned)
{
mesh->skin.controller.AdvanceTime(dt);
mesh->skin.skeleton.GetMatrices(skinTempBuffer);
skinBuffer->Update(skinTempBuffer, PerObjectSkinningVSDataSize);
}
}
void bind()
{
IRenderer* renderer = CG::me()->GetRenderer();
renderer->SetVSConstantBuffer(perObjectCb, 0);
renderer->SetVertexBuffer(mesh->vertexData);
renderer->SetIndexBuffer(mesh->indexData);
renderer->SetInputLayout(mesh->inputLayout);
renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST);
if(mesh->IsSkinned)
CG::me()->GetRenderer()->SetVSConstantBuffer(skinBuffer, 5);
}
void render(int submesh)
{
CG::me()->GetRenderer()->DrawIndexed(mesh->subsets[submesh].Offset,mesh->subsets[submesh].Length);
}
int getSumbeshCount() const
{
return mesh->subsetCount;
}
void selectLod(int lodNum)
{
mesh = lods[lodNum].mesh;
bBox = mesh->bBox;
}
void selectLod(const Camera* cam)
{
}
void setLod(IMesh* _mesh, float distance)
{
MeshLOD lod;
lod.distance = distance;
lod.mesh = _mesh;
int lodCount = lods.size();
if(!lodCount)
{
mesh = _mesh;
lods.push_back(lod);
Name = lods[0].mesh->Name;
return;
}
for(std::vector<MeshLOD>::iterator iter = lods.begin(); iter!= lods.end(); ++iter)
{
if(iter->distance > distance)
lods.insert(iter,1,lod);
}
Name = lods[0].mesh->Name;
}
NodeType getType()
{
return NT_MESH;
}
};
}
#endif // IObjectMesh_h__
+15
View File
@@ -0,0 +1,15 @@
#include "IRenderOutput.h"
namespace LifeGraphics
{
IRenderOutput::IRenderOutput(LifeCore::IRenderWindow* out_window, ISwapChain* out_swapchain){
window = out_window;
swap_chain = out_swapchain;
}
LifeCore::IRenderWindow* IRenderOutput::GetWindow(){
return window;
}
ISwapChain* IRenderOutput::GetSwapChain(){
return swap_chain;
}
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef IRenderOutput_h__
#define IRenderOutput_h__
#include <IRenderWindow.h>
#include "ISwapChain.h"
namespace LifeGraphics
{
class IRenderOutput
{
public:
IRenderOutput(LifeCore::IRenderWindow* out_window, ISwapChain* out_swapchain);
LifeCore::IRenderWindow* GetWindow();
ISwapChain* GetSwapChain();
private:
LifeCore::IRenderWindow* window;
ISwapChain* swap_chain;
};
}
#endif // IRenderOutput_h__
+37
View File
@@ -0,0 +1,37 @@
#ifndef IRESOURCE_H__
#define IRESOURCE_H__
//#include "IDataStream.h"
#include <LString.h>
namespace LifeGraphics
{
class IResource
{
protected:
int _refCount;
public:
int CreationTime;
int MemoryUsed;
IResource()
:_refCount(0)
{
Grab();
}
size_t Id;
size_t GetID()
{
return Id;
}
String Name;
void Grab(){_refCount++;}
void Release(){_refCount--;}
int RefCount(){return _refCount;}
virtual ~IResource(){}
// virtual void Load(Core::IDataStream* src) = 0;
// virtual void CompleteAsyncRequest(IResource* source) = 0;
};
}
#endif
+88
View File
@@ -0,0 +1,88 @@
#ifndef IResourceCollection_h__
#define IResourceCollection_h__
#include <map>
#include <memory>
#include "resource_ptr.h"
#include "LString.h"
#include "Globals.h"
namespace LifeGraphics
{
template<typename T>
class IResourceCollection
{
private:
typedef std::map<int, resource_ptr<T>> resourceMap;
int resCnt;
resourceMap collection;
int lastId;
int NextId()
{
return lastId++;
}
public:
int CollectGarbage()
{
int cnt = collection.size();
for(int i = 0; i < cnt; i++)
{
}
}
IResourceCollection()
{
resCnt = 0;
lastId = 0;
}
~IResourceCollection()
{
}
int push_back(resource_ptr<T> resource)
{
resource->Id = NextId();
collection[resource->Id] = resource;
resCnt++;
return resource->Id;
}
void Release()
{
for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++)
{
it->second->Release();
}
}
int Exists(const String& name)
{
for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++)
{
if(it->second->Name == name)
{
return 1;
}
}
return 0;
}
int GetResource(int id, resource_ptr<T>& resource)
{
resource = collection[id];
return 0;
}
int GetResource(String name, resource_ptr<T>& resource)
{
for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++)
{
if(it->second->Name == name)
{
resource = it->second;
return 1;
}
}
return 0;
}
};
}
#endif
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
#ifndef ISkinnedMesh_h__
#define ISkinnedMesh_h__
#include "IMesh.h"
namespace LifeGraphics
{
class ISkinnedMesh : public IMesh
{
};
}
#endif // ISkinnedMesh_h__
+23
View File
@@ -0,0 +1,23 @@
#ifndef ISwapChain_h__
#define ISwapChain_h__
#include "render/ITexture2D.h"
#include "Types.h"
#include <delegate/Delegate.h>
namespace LifeGraphics
{
class ISwapChain{
public:
EVENT1(SwapChainEvent, ISwapChain*);
SwapChainEvent Event_Resized;
SwapChainEvent Event_Presented;
virtual LifeGraphics::ITexture2D* GetBackBuffer(uint8 id) = 0;
virtual LifeGraphics::ITexture2D* GetDepthBuffer(uint8 id) = 0;
virtual void Resize(uint16 width, uint16 height) = 0;
virtual void Present() = 0;
virtual ~ISwapChain(){}
};
}
#endif // ISwapChain_h__
+24
View File
@@ -0,0 +1,24 @@
#ifndef LifeDebug_h__
#define LifeDebug_h__
//#define _CRTDBG_MAP_ALLOC
//#include <crtdbg.h>
/*
#ifdef _CRTDBG_MAP_ALLOC
#define malloc(s) _malloc_dbg(s,_NORMAL_BLOCK,__FILE__,__LINE__)
#define calloc(c,s) _calloc_dbg(c,s,_NORMAL_BLOCK,__FILE__,__LINE__)
#define realloc(p,s) _realloc_dbg(p,s,_NORMAL_BLOCK,__FILE__,__LINE__)
#define _expand(p,s) _expand_dbg(p,s,_NORMAL_BLOCK,__FILE__,__LINE__)
#define free(p) _free_dbg(p,_NORMAL_BLOCK)
#define _msize(p) _msize_dbg(p,_NORMAL_BLOCK)
#endif
#ifdef _DEBUG
#ifdef _CRTDBG_MAP_ALLOC
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif */
#endif // LifeDebug_h__
+1
View File
@@ -0,0 +1 @@
// ADD PREDEFINED MACROS HERE!
+85
View File
@@ -0,0 +1,85 @@
#include "LifeEngine.h"
#define COMPILE_WITH_DX11
//#define COMPILE_WITH_SW
#include "Globals.h"
#include "IScene.h"
#ifdef COMPILE_WITH_DX11
#include "render/dx11/RendererDX11.h"
#endif
#ifdef COMPILE_WITH_SW
#include "RendererSoftware.h"
#endif
namespace LifeGraphics
{
LifeEngine::LifeEngine()
:engine_time(0.01f), appTime(0.0f)
{
}
LifeEngine::~LifeEngine()
{
g_pRenderer->BeginCleanup();
ResourceManager::me()->ReleaseResources();
g_pRenderer->EndCleanup();
SAFE_DELETE(g_pRenderer);
}
PluginServer* LifeEngine::GetPluginServer()
{
return &g_pluginServer;
}
IRenderer* LifeEngine::Init(LifeGraphics::RENDERER_TYPE type, RenderParams params)
{
switch(type)
{
case RT_DIRECTX_9:
//Nothing for now
break;
case RT_DIRECTX_10:
/*g_pluginServer.LoadPlugin("RendererDX10.dll");
g_pRenderer = g_pluginServer.GetRenderer(0);
printf(g_pRenderer->GetRendererName().c_str());
g_pRenderer->Open(params);*/
break;
case RT_DIRECTX_11:
//g_pluginServer.LoadPlugin("RendererDX11.dll");
g_pRenderer = new RendererDX11();
g_pRenderer->Open(params);
break;
}
//window = params.Window;
//window->Event_Resize += NewDelegate(this, &Video::LifeEngine::onWindowResize);
CG::me()->SetRenderer(g_pRenderer);
debugDrawer = new IDebugDrawer(g_pRenderer);
return g_pRenderer;
}
IRenderer* LifeEngine::GetRenderer()
{
return g_pRenderer;
}
void LifeEngine::onWindowResize(LifeCore::IRenderWindow* window)
{
printf("LOOOOOL!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n WINDOW RESIZED!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!\n");
}
void LifeEngine::RenderScene(LifeGraphics::IScene* scene, IRenderOutput* output)
{
scene->Render(output);
}
IRenderOutput* LifeEngine::CreateRenderOutput(LifeCore::IRenderWindow* wnd){
LifeGraphics::ISwapChain* sc = GetRenderer()->CreateSwapChain(wnd);
if(sc == nullptr)
return nullptr;
return new IRenderOutput(wnd, sc);
}
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef LifeEngine_h__
#define LifeEngine_h__
#include "render/IRenderer.h"
//#include "RendererDX10.h"
#include "render/RenderParams.h"
#include "PluginServer.h"
#include "camera/Camera.h"
#include "Timer.h"
#include "LString.h"
#include "IScene.h"
#include "debug/IDebugDrawer.h"
#include "RenderWindow.h"
#include "IRenderOutput.h"
namespace LifeGraphics
{
class LIFE_EXPORTS LifeEngine
{
public:
float appTime;
IDebugDrawer* debugDrawer;
float engine_time;
LifeEngine();
~LifeEngine();
IRenderer* Init(LifeGraphics::RENDERER_TYPE type, RenderParams params);
IRenderer* GetRenderer();
PluginServer* GetPluginServer();
void RenderScene(LifeGraphics::IScene* scene, IRenderOutput* output);
ResourceManager* GetResourceManager()
{
return ResourceManager::me();
}
float FrameEnd()
{
systemTimer.Stop();
engine_time = systemTimer.getTimeElapsed();
appTime += engine_time;
systemTimer.Start();
ResourceManager::me()->CollectGarbage(engine_time);
return engine_time;
}
float GetTimeElapsed()
{
return engine_time;
}
IRenderOutput* CreateRenderOutput(LifeCore::IRenderWindow* wnd);
private:
void onWindowResize(LifeCore::IRenderWindow* window);
IRenderer* g_pRenderer;
PluginServer g_pluginServer;
LifeCore::Timer systemTimer;
};
}
#endif // LifeEngine_h__
+561
View File
@@ -0,0 +1,561 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AnimationController.h" />
<ClInclude Include="AnimationFrame.h" />
<ClInclude Include="AnimationTrack.h" />
<ClInclude Include="Bone.h" />
<ClInclude Include="BoneTransform.h" />
<ClInclude Include="BoundingSphere.h" />
<ClInclude Include="camera\Camera.h" />
<ClInclude Include="camera\Frustum.h" />
<ClInclude Include="CG.h" />
<ClInclude Include="constants.h" />
<ClInclude Include="CustomSwapChain.h" />
<ClInclude Include="DayTime.h" />
<ClInclude Include="debug\IDebugDrawer.h" />
<ClInclude Include="GeometrySubset.h" />
<ClInclude Include="Globals.h" />
<ClInclude Include="IGraphicsNode.h" />
<ClInclude Include="IMesh.h" />
<ClInclude Include="include\renderpath\RenderPathSpotShadow.h" />
<ClInclude Include="include\Singleton.h" />
<ClInclude Include="IObject.h" />
<ClInclude Include="IObjectMesh.h" />
<ClInclude Include="IRenderOutput.h" />
<ClInclude Include="IResource.h" />
<ClInclude Include="IResourceCollection.h" />
<ClInclude Include="IScene.h" />
<ClInclude Include="ISkinnedMesh.h" />
<ClInclude Include="ISwapChain.h" />
<ClInclude Include="LifeDebug.h" />
<ClInclude Include="LifeEngine.h" />
<ClInclude Include="Light.h" />
<ClInclude Include="MeshManager.h" />
<ClInclude Include="PassGBuffer.h" />
<ClInclude Include="passPSSM.h" />
<ClInclude Include="Plugin.h" />
<ClInclude Include="PluginServer.h" />
<ClInclude Include="pugiconfig.hpp" />
<ClInclude Include="pugixml.hpp" />
<ClInclude Include="pugixml\contrib\foreach.hpp" />
<ClInclude Include="pugixml\src\pugiconfig.hpp" />
<ClInclude Include="pugixml\src\pugixml.hpp" />
<ClInclude Include="queries\IFrustumQuery.h" />
<ClInclude Include="queries\INodeQuery.h" />
<ClInclude Include="queries\IQuery.h" />
<ClInclude Include="Rectangle2D.h" />
<ClInclude Include="RenderOperation.h" />
<ClInclude Include="RenderPass.h" />
<ClInclude Include="renderpath\IRenderPath.h" />
<ClInclude Include="renderpath\IRenderPathShadow.h" />
<ClInclude Include="renderpath\RenderPathDefault.h" />
<ClInclude Include="renderpath\RenderPathDeferred.h" />
<ClInclude Include="renderpath\RenderPathForward.h" />
<ClInclude Include="renderpath\RenderPathOmniShadow.h" />
<ClInclude Include="renderpath\RenderPathSpotShadow.h" />
<ClInclude Include="RenderQueue.h" />
<ClInclude Include="render\dx11\IBlendState11.h" />
<ClInclude Include="render\dx11\IConstantBuffer11.h" />
<ClInclude Include="render\dx11\IDepthStencilState11.h" />
<ClInclude Include="render\dx11\IIndexBuffer11.h" />
<ClInclude Include="render\dx11\IInputLayout11.h" />
<ClInclude Include="render\dx11\IPixelShader11.h" />
<ClInclude Include="render\dx11\IRasterizerState11.h" />
<ClInclude Include="render\dx11\IRenderTargetViewDX11.h" />
<ClInclude Include="render\dx11\IShaderResourceView11.h" />
<ClInclude Include="render\dx11\ISurface11.h" />
<ClInclude Include="render\dx11\ISwapChain11.h" />
<ClInclude Include="render\dx11\ITexture2D11.h" />
<ClInclude Include="render\dx11\ITextureSampler11.h" />
<ClInclude Include="render\dx11\IVertexBuffer11.h" />
<ClInclude Include="render\dx11\IVertexShader11.h" />
<ClInclude Include="render\dx11\RendererDX11.h" />
<ClInclude Include="render\Enums.h" />
<ClInclude Include="render\IBlendState.h" />
<ClInclude Include="render\IConstantBuffer.h" />
<ClInclude Include="render\IConstantMapping.h" />
<ClInclude Include="render\IDataBuffer.h" />
<ClInclude Include="render\IDepthStencilState.h" />
<ClInclude Include="render\IIndexBuffer.h" />
<ClInclude Include="render\IInputElement.h" />
<ClInclude Include="render\IInputLayout.h" />
<ClInclude Include="render\IMacroDefine.h" />
<ClInclude Include="render\IMaterial.h" />
<ClInclude Include="render\IMaterialProxy.h" />
<ClInclude Include="render\IRasterizerState.h" />
<ClInclude Include="render\IRenderer.h" />
<ClInclude Include="render\IRenderTargetView.h" />
<ClInclude Include="render\IShader.h" />
<ClInclude Include="render\IShaderResourceView.h" />
<ClInclude Include="render\ISurface.h" />
<ClInclude Include="render\ITexture2D.h" />
<ClInclude Include="render\ITextureContainer.h" />
<ClInclude Include="render\ITextureCube.h" />
<ClInclude Include="render\ITextureDescription.h" />
<ClInclude Include="render\ITextureSampler.h" />
<ClInclude Include="render\IVertexBuffer.h" />
<ClInclude Include="render\IVideoTexture.h" />
<ClInclude Include="render\PostDOF.h" />
<ClInclude Include="render\PostEffect.h" />
<ClInclude Include="render\PosteffectManager.h" />
<ClInclude Include="render\PostHDR.h" />
<ClInclude Include="render\PostSSAO.h" />
<ClInclude Include="render\RendererDX10.h" />
<ClInclude Include="render\RendererSoftware.h" />
<ClInclude Include="render\RenderParams.h" />
<ClInclude Include="render\software\IBlendStateS.h" />
<ClInclude Include="render\software\IConstantBufferS.h" />
<ClInclude Include="render\software\IDepthStencilStateS.h" />
<ClInclude Include="render\software\IIndexBufferS.h" />
<ClInclude Include="render\software\IInputLayoutS.h" />
<ClInclude Include="render\software\IPixelShaderS.h" />
<ClInclude Include="render\software\IRasterizerStateS.h" />
<ClInclude Include="render\software\IRenderTargetViewS.h" />
<ClInclude Include="render\software\IShaderResourceViewS.h" />
<ClInclude Include="render\software\ITexture2DS.h" />
<ClInclude Include="render\software\ITextureSamplerS.h" />
<ClInclude Include="render\software\IVertexBufferS.h" />
<ClInclude Include="render\software\IVertexShaderS.h" />
<ClInclude Include="ResourceManager.h" />
<ClInclude Include="resource_ptr.h" />
<ClInclude Include="shaders\IShaderFactorySource.h" />
<ClInclude Include="shaders\IShaderGraph.h" />
<ClInclude Include="shaders\IShaderGraphCompiler.h" />
<ClInclude Include="shaders\IShaderGraphNode.h" />
<ClInclude Include="shaders\IShaderGraphNodeFactory.h" />
<ClInclude Include="shaders\IShaderGraphNodePort.h" />
<ClInclude Include="shaders\IShaderTypes.h" />
<ClInclude Include="shaders\ShaderGraphCompilerHLSL.h" />
<ClInclude Include="ShadowMapManager.h" />
<ClInclude Include="Skeleton.h" />
<ClInclude Include="SkinInfo.h" />
<ClInclude Include="Sky.h" />
<ClInclude Include="src\AnimationController.h" />
<ClInclude Include="src\AnimationFrame.h" />
<ClInclude Include="src\AnimationTrack.h" />
<ClInclude Include="src\Bone.h" />
<ClInclude Include="src\BoneTransform.h" />
<ClInclude Include="src\BoundingSphere.h" />
<ClInclude Include="src\camera\Camera.h" />
<ClInclude Include="src\camera\Frustum.h" />
<ClInclude Include="src\CG.h" />
<ClInclude Include="src\constants.h" />
<ClInclude Include="src\CustomSwapChain.h" />
<ClInclude Include="src\DayTime.h" />
<ClInclude Include="src\debug\IDebugDrawer.h" />
<ClInclude Include="src\GeometrySubset.h" />
<ClInclude Include="src\Globals.h" />
<ClInclude Include="src\IGraphicsNode.h" />
<ClInclude Include="src\IMesh.h" />
<ClInclude Include="src\IObject.h" />
<ClInclude Include="src\IObjectMesh.h" />
<ClInclude Include="src\IRenderOutput.h" />
<ClInclude Include="src\IResource.h" />
<ClInclude Include="src\IResourceCollection.h" />
<ClInclude Include="src\IScene.h" />
<ClInclude Include="src\ISkinnedMesh.h" />
<ClInclude Include="src\ISwapChain.h" />
<ClInclude Include="src\LifeDebug.h" />
<ClInclude Include="src\LifeEngine.h" />
<ClInclude Include="src\Light.h" />
<ClInclude Include="src\MeshManager.h" />
<ClInclude Include="src\PassGBuffer.h" />
<ClInclude Include="src\passPSSM.h" />
<ClInclude Include="src\Plugin.h" />
<ClInclude Include="src\PluginServer.h" />
<ClInclude Include="src\pugiconfig.hpp" />
<ClInclude Include="src\pugixml.hpp" />
<ClInclude Include="src\pugixml\contrib\foreach.hpp" />
<ClInclude Include="src\pugixml\src\pugiconfig.hpp" />
<ClInclude Include="src\pugixml\src\pugixml.hpp" />
<ClInclude Include="src\queries\IFrustumQuery.h" />
<ClInclude Include="src\queries\INodeQuery.h" />
<ClInclude Include="src\queries\IQuery.h" />
<ClInclude Include="src\Rectangle2D.h" />
<ClInclude Include="src\RenderOperation.h" />
<ClInclude Include="src\RenderPass.h" />
<ClInclude Include="src\renderpath\IRenderPath.h" />
<ClInclude Include="src\renderpath\IRenderPathShadow.h" />
<ClInclude Include="src\renderpath\RenderPathDefault.h" />
<ClInclude Include="src\renderpath\RenderPathDeferred.h" />
<ClInclude Include="src\renderpath\RenderPathForward.h" />
<ClInclude Include="src\renderpath\RenderPathOmniShadow.h" />
<ClInclude Include="src\renderpath\RenderPathSpotShadow.h" />
<ClInclude Include="src\RenderQueue.h" />
<ClInclude Include="src\render\dx11\IBlendState11.h" />
<ClInclude Include="src\render\dx11\IConstantBuffer11.h" />
<ClInclude Include="src\render\dx11\IDepthStencilState11.h" />
<ClInclude Include="src\render\dx11\IIndexBuffer11.h" />
<ClInclude Include="src\render\dx11\IInputLayout11.h" />
<ClInclude Include="src\render\dx11\IPixelShader11.h" />
<ClInclude Include="src\render\dx11\IRasterizerState11.h" />
<ClInclude Include="src\render\dx11\IRenderTargetViewDX11.h" />
<ClInclude Include="src\render\dx11\IShaderResourceView11.h" />
<ClInclude Include="src\render\dx11\ISurface11.h" />
<ClInclude Include="src\render\dx11\ISwapChain11.h" />
<ClInclude Include="src\render\dx11\ITexture2D11.h" />
<ClInclude Include="src\render\dx11\ITextureSampler11.h" />
<ClInclude Include="src\render\dx11\IVertexBuffer11.h" />
<ClInclude Include="src\render\dx11\IVertexShader11.h" />
<ClInclude Include="src\render\dx11\RendererDX11.h" />
<ClInclude Include="src\render\Enums.h" />
<ClInclude Include="src\render\IBlendState.h" />
<ClInclude Include="src\render\IConstantBuffer.h" />
<ClInclude Include="src\render\IConstantMapping.h" />
<ClInclude Include="src\render\IDataBuffer.h" />
<ClInclude Include="src\render\IDepthStencilState.h" />
<ClInclude Include="src\render\IIndexBuffer.h" />
<ClInclude Include="src\render\IInputElement.h" />
<ClInclude Include="src\render\IInputLayout.h" />
<ClInclude Include="src\render\IMacroDefine.h" />
<ClInclude Include="src\render\IMaterial.h" />
<ClInclude Include="src\render\IMaterialProxy.h" />
<ClInclude Include="src\render\IRasterizerState.h" />
<ClInclude Include="src\render\IRenderer.h" />
<ClInclude Include="src\render\IRenderTargetView.h" />
<ClInclude Include="src\render\IShader.h" />
<ClInclude Include="src\render\IShaderResourceView.h" />
<ClInclude Include="src\render\ISurface.h" />
<ClInclude Include="src\render\ITexture2D.h" />
<ClInclude Include="src\render\ITextureContainer.h" />
<ClInclude Include="src\render\ITextureCube.h" />
<ClInclude Include="src\render\ITextureDescription.h" />
<ClInclude Include="src\render\ITextureSampler.h" />
<ClInclude Include="src\render\IVertexBuffer.h" />
<ClInclude Include="src\render\IVideoTexture.h" />
<ClInclude Include="src\render\PostDOF.h" />
<ClInclude Include="src\render\PostEffect.h" />
<ClInclude Include="src\render\PosteffectManager.h" />
<ClInclude Include="src\render\PostHDR.h" />
<ClInclude Include="src\render\PostSSAO.h" />
<ClInclude Include="src\render\RendererDX10.h" />
<ClInclude Include="src\render\RendererSoftware.h" />
<ClInclude Include="src\render\RenderParams.h" />
<ClInclude Include="src\render\software\IBlendStateS.h" />
<ClInclude Include="src\render\software\IConstantBufferS.h" />
<ClInclude Include="src\render\software\IDepthStencilStateS.h" />
<ClInclude Include="src\render\software\IIndexBufferS.h" />
<ClInclude Include="src\render\software\IInputLayoutS.h" />
<ClInclude Include="src\render\software\IPixelShaderS.h" />
<ClInclude Include="src\render\software\IRasterizerStateS.h" />
<ClInclude Include="src\render\software\IRenderTargetViewS.h" />
<ClInclude Include="src\render\software\IShaderResourceViewS.h" />
<ClInclude Include="src\render\software\ITexture2DS.h" />
<ClInclude Include="src\render\software\ITextureSamplerS.h" />
<ClInclude Include="src\render\software\IVertexBufferS.h" />
<ClInclude Include="src\render\software\IVertexShaderS.h" />
<ClInclude Include="src\ResourceManager.h" />
<ClInclude Include="src\resource_ptr.h" />
<ClInclude Include="src\shaders\IShaderFactorySource.h" />
<ClInclude Include="src\shaders\IShaderGraph.h" />
<ClInclude Include="src\shaders\IShaderGraphCompiler.h" />
<ClInclude Include="src\shaders\IShaderGraphNode.h" />
<ClInclude Include="src\shaders\IShaderGraphNodeFactory.h" />
<ClInclude Include="src\shaders\IShaderGraphNodePort.h" />
<ClInclude Include="src\shaders\IShaderTypes.h" />
<ClInclude Include="src\shaders\ShaderGraphCompilerHLSL.h" />
<ClInclude Include="src\ShadowMapManager.h" />
<ClInclude Include="src\Skeleton.h" />
<ClInclude Include="src\SkinInfo.h" />
<ClInclude Include="src\Sky.h" />
<ClInclude Include="src\targetver.h" />
<ClInclude Include="src\Terrain.h" />
<ClInclude Include="src\TypesVideo.h" />
<ClInclude Include="src\vegetation\PlantManager.h" />
<ClInclude Include="src\Vertex.h" />
<ClInclude Include="src\XML.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="Terrain.h" />
<ClInclude Include="TypesVideo.h" />
<ClInclude Include="vegetation\PlantManager.h" />
<ClInclude Include="Vertex.h" />
<ClInclude Include="XML.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Camera.cpp" />
<ClCompile Include="CG.cpp" />
<ClCompile Include="CustomSwapChain.cpp" />
<ClCompile Include="IRenderOutput.cpp" />
<ClCompile Include="LifeEngine.cpp" />
<ClCompile Include="MeshManager.cpp" />
<ClCompile Include="Plugin.cpp" />
<ClCompile Include="PluginServer.cpp" />
<ClCompile Include="pugixml.cpp" />
<ClCompile Include="pugixml\src\pugixml.cpp" />
<ClCompile Include="queries\IFrustumQuery.cpp" />
<ClCompile Include="renderpath\RenderPathDefault.cpp" />
<ClCompile Include="renderpath\RenderPathOmniShadow.cpp" />
<ClCompile Include="renderpath\RenderPathSpotShadow.cpp" />
<ClCompile Include="render\dx11\IConstantBuffer11.cpp" />
<ClCompile Include="render\dx11\ISurface11.cpp" />
<ClCompile Include="render\dx11\ISwapChain11.cpp" />
<ClCompile Include="render\dx11\RendererDX11.cpp" />
<ClCompile Include="render\IConstantMapping.cpp" />
<ClCompile Include="render\IMaterial.cpp" />
<ClCompile Include="render\IMaterialProxy.cpp" />
<ClCompile Include="render\IRenderer.cpp" />
<ClCompile Include="render\PostSSAO.cpp" />
<ClCompile Include="render\RendererDX10.cpp" />
<ClCompile Include="render\software\RendererSoftware.cpp" />
<ClCompile Include="ResourceManager.cpp" />
<ClCompile Include="scene\IScene.cpp" />
<ClCompile Include="scene\ISceneManager.cpp" />
<ClCompile Include="shaders\IShaderFactorySource.cpp" />
<ClCompile Include="shaders\IShaderGraph.cpp" />
<ClCompile Include="shaders\IShaderGraphNode.cpp" />
<ClCompile Include="shaders\IShaderGraphNodeFactory.cpp" />
<ClCompile Include="shaders\IShaderGraphNodePort.cpp" />
<ClCompile Include="shaders\ShaderGraphCompilerHLSL.cpp" />
<ClCompile Include="src\Camera.cpp" />
<ClCompile Include="src\CG.cpp" />
<ClCompile Include="src\CustomSwapChain.cpp" />
<ClCompile Include="src\IRenderOutput.cpp" />
<ClCompile Include="src\LifeEngine.cpp" />
<ClCompile Include="src\MeshManager.cpp" />
<ClCompile Include="src\Plugin.cpp" />
<ClCompile Include="src\PluginServer.cpp" />
<ClCompile Include="src\pugixml.cpp" />
<ClCompile Include="src\pugixml\docs\samples\custom_memory_management.cpp" />
<ClCompile Include="src\pugixml\docs\samples\include.cpp" />
<ClCompile Include="src\pugixml\docs\samples\load_error_handling.cpp" />
<ClCompile Include="src\pugixml\docs\samples\load_file.cpp" />
<ClCompile Include="src\pugixml\docs\samples\load_memory.cpp" />
<ClCompile Include="src\pugixml\docs\samples\load_options.cpp" />
<ClCompile Include="src\pugixml\docs\samples\load_stream.cpp" />
<ClCompile Include="src\pugixml\docs\samples\modify_add.cpp" />
<ClCompile Include="src\pugixml\docs\samples\modify_base.cpp" />
<ClCompile Include="src\pugixml\docs\samples\modify_remove.cpp" />
<ClCompile Include="src\pugixml\docs\samples\save_custom_writer.cpp" />
<ClCompile Include="src\pugixml\docs\samples\save_file.cpp" />
<ClCompile Include="src\pugixml\docs\samples\save_options.cpp" />
<ClCompile Include="src\pugixml\docs\samples\save_stream.cpp" />
<ClCompile Include="src\pugixml\docs\samples\save_subtree.cpp" />
<ClCompile Include="src\pugixml\docs\samples\traverse_base.cpp" />
<ClCompile Include="src\pugixml\docs\samples\traverse_iter.cpp" />
<ClCompile Include="src\pugixml\docs\samples\traverse_predicate.cpp" />
<ClCompile Include="src\pugixml\docs\samples\traverse_walker.cpp" />
<ClCompile Include="src\pugixml\docs\samples\xpath_error.cpp" />
<ClCompile Include="src\pugixml\docs\samples\xpath_query.cpp" />
<ClCompile Include="src\pugixml\docs\samples\xpath_select.cpp" />
<ClCompile Include="src\pugixml\docs\samples\xpath_variables.cpp" />
<ClCompile Include="src\pugixml\src\pugixml.cpp" />
<ClCompile Include="src\queries\IFrustumQuery.cpp" />
<ClCompile Include="src\render\RendererDX10.cpp" />
<ClCompile Include="src\renderpath\RenderPathDefault.cpp" />
<ClCompile Include="src\renderpath\RenderPathOmniShadow.cpp" />
<ClCompile Include="src\renderpath\RenderPathSpotShadow.cpp" />
<ClCompile Include="src\render\dx11\IConstantBuffer11.cpp" />
<ClCompile Include="src\render\dx11\ISurface11.cpp" />
<ClCompile Include="src\render\dx11\ISwapChain11.cpp" />
<ClCompile Include="src\render\dx11\RendererDX11.cpp" />
<ClCompile Include="src\render\IConstantMapping.cpp" />
<ClCompile Include="src\render\IMaterial.cpp" />
<ClCompile Include="src\render\IMaterialProxy.cpp" />
<ClCompile Include="src\render\IRenderer.cpp" />
<ClCompile Include="src\render\PostSSAO.cpp" />
<ClCompile Include="src\render\software\RendererSoftware.cpp" />
<ClCompile Include="src\ResourceManager.cpp" />
<ClCompile Include="src\scene\IScene.cpp" />
<ClCompile Include="src\scene\ISceneManager.cpp" />
<ClCompile Include="src\shaders\IShaderFactorySource.cpp" />
<ClCompile Include="src\shaders\IShaderGraph.cpp" />
<ClCompile Include="src\shaders\IShaderGraphNode.cpp" />
<ClCompile Include="src\shaders\IShaderGraphNodeFactory.cpp" />
<ClCompile Include="src\shaders\IShaderGraphNodePort.cpp" />
<ClCompile Include="src\shaders\ShaderGraphCompilerHLSL.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="LifeEngine.config" />
<None Include="src\pugixml\docs\manual.html" />
<None Include="src\pugixml\docs\manual\access.html" />
<None Include="src\pugixml\docs\manual\apiref.html" />
<None Include="src\pugixml\docs\manual\changes.html" />
<None Include="src\pugixml\docs\manual\dom.html" />
<None Include="src\pugixml\docs\manual\install.html" />
<None Include="src\pugixml\docs\manual\loading.html" />
<None Include="src\pugixml\docs\manual\modify.html" />
<None Include="src\pugixml\docs\manual\saving.html" />
<None Include="src\pugixml\docs\manual\toc.html" />
<None Include="src\pugixml\docs\manual\xpath.html" />
<None Include="src\pugixml\docs\quickstart.html" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{54BC1734-E9F0-4170-A267-91E84F3EACB5}</ProjectGuid>
<RootNamespace>LifeEngine</RootNamespace>
<Keyword>Win32Proj</Keyword>
<SccProjectName>&lt;Project Location In Database&gt;</SccProjectName>
<SccAuxPath>&lt;Source Control Database&gt;</SccAuxPath>
<SccLocalPath>&lt;Local Binding Root of Project&gt;</SccLocalPath>
<SccProvider>Mercurial Source Control Package</SccProvider>
<VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''">$(VCTargetsPath11)</VCTargetsPath>
<ProjectName>LifeGraphics</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(ProjectName)\lib\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(ProjectName)\lib\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(ProjectName)\tmp\$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\$(ProjectName)</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(ProjectName)\lib\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">lib\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(ProjectName)\tmp\$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Configuration)\</IntDir>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectName)_d</TargetName>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName)_d</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(REPO_DIR)\zlib-1.2.5;$(DXSDK_DIR)\Include;$(SolutionDir)/LifeCore/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<OpenMPSupport>false</OpenMPSupport>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<TreatWarningAsError>false</TreatWarningAsError>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ObjectFileName>$(IntDir)</ObjectFileName>
</ClCompile>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LifeCore_d.lib;d3dx11.lib;DXGI.lib;d3d11.lib;d3dcompiler.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<OpenMPSupport>false</OpenMPSupport>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<TreatWarningAsError>false</TreatWarningAsError>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ObjectFileName>$(IntDir)</ObjectFileName>
</ClCompile>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LifeCore_d.lib;freetype243_D.lib;d3dx11.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;$(SolutionDir)/LifeCore/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<OpenMPSupport>true</OpenMPSupport>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LifeCore.lib;freetype243.lib;d3dx11.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<OpenMPSupport>true</OpenMPSupport>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>LifeCore.lib;freetype243.lib;d3dx11.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+204
View File
@@ -0,0 +1,204 @@
#ifndef Light_h__
#define Light_h__
#include "IGraphicsNode.h"
#include "math/Vector3D.h"
#include "math/Vector4D.h"
#include "camera/Frustum.h"
namespace LifeGraphics
{
enum LIGHT_TYPE
{
LT_POINT = 0,
LT_SPOT = 1,
LT_DIRECTIONAL = 2
};
class Light : public IGraphicsNode
{
public:
Light(LIGHT_TYPE lt)
: range(1), innerAngle(0.5f), outerAngle(0.6f), direction(0.0f, -1.0f, 0.0f),
position(0.0f,0.0f, 0.0f), up(0.0f, 1.0f, 0.0f), color(1.0f, 0.0f, 1.0f),
intensity(1.0f), isMatrixValid(false), castShadows(false)
{
lightType = lt;
}
Light()
: lightType(LT_POINT), range(1), innerAngle(0.5f), outerAngle(0.6f), direction(0.0f, -1.0f, 0.0f),
position(0.0f,0.0f, 0.0f), up(0.0f, 1.0f, 0.0f), color(1.0f, 0.0f, 1.0f),
intensity(1.0f), isMatrixValid(false), castShadows(false)
{
}
~Light()
{
}
NodeType getType()
{
return NT_LIGHT;
}
void setDirection(const LifeMath::float3& dir)
{
direction = dir;
isMatrixValid = false;
//this->bSphere.center = this->_position;
//this->bSphere.radius = this->range;
}
const LifeMath::float4x4& getMatrix()
{
fixupTransform();
return matrix;
}
const LifeMath::float4x4& getView()
{
fixupTransform();
return mView;
}
const LifeMath::float4x4& getProj()
{
fixupTransform();
return mProj;
}
LifeMath::float3 getDirection()
{
fixupTransform();
return direction;
}
LifeMath::float3 getPosition()
{
fixupTransform();
return position;
}
void setInnerAngle(float angle)
{
innerAngle = angle;
if(innerAngle > 3.1415f)
innerAngle = 3.1415f;
isMatrixValid = false;
}
float getInnerAngle()
{
return innerAngle;
}
void setOuterAngle(float angle)
{
outerAngle = angle;
if(outerAngle<innerAngle)
outerAngle = innerAngle;
isMatrixValid = false;
}
float getOuterAngle()
{
return outerAngle;
}
void setRange(float _range)
{
range = _range;
this->bSphere.radius = this->range;
isMatrixValid = false;
}
float getRange()
{
return range;
}
void update(float dt)
{
fixupTransform();
}
LifeMath::float4x4 getMeshMatrix()
{
float baseRadius = tanf(outerAngle * 0.5f) * range * 1.1f;
LifeMath::float4x4 b;
Mat4x4Scaling(baseRadius, baseRadius, range, b);
LifeMath::float3 right;
LifeMath::float3 orthoUp;
LifeMath::float3 dir = direction - position;
LifeMath::Vec3Normalize(&dir);
LifeMath::Vec3Cross(up, dir, right);
LifeMath::Vec3Cross(dir, right, orthoUp);
LifeMath::Vec3Normalize(&orthoUp);
LifeMath::float4x4 r;
Mat4x4Identity(&r);
r.M11 = right.X;
r.M12 = right.Y;
r.M13 = right.Z;
r.M21 = orthoUp.X;
r.M22 = orthoUp.Y;
r.M23 = orthoUp.Z;
r.M31 = dir.X;
r.M32 = dir.Y;
r.M33 = dir.Z;
LifeMath::float3 pos = transform->GetPosition();
r.M41 = pos.X;
r.M42 = pos.Y;
r.M43 = pos.Z;
return b * r;
}
Frustum* getFrustum()
{
if(!isMatrixValid)
computeMatrix();
return &frustum;
}
LIGHT_TYPE lightType;
LifeMath::float3 color;
float specularPower;
float intensity;
bool castShadows;
private:
void fixupTransform()
{
if(position!= transform->GetPosition())
{
position = transform->GetPosition();
isMatrixValid = false;
this->bSphere.center = position;
this->bSphere.radius = range;
}
if(!isMatrixValid)
{
computeMatrix();
}
}
void computeMatrix()
{
LifeMath::float3 dir = direction - position;
LifeMath::Vec3Normalize(&dir);
float angle = LifeMath::Vec3Dot(&up, &dir);
if((angle>0.9f) | (angle<-0.9f))
up = LifeMath::float3(0.0f,0.0f,1.0f);
else
up = LifeMath::float3(0.0f,1.0f,0.0f);
LifeMath::Mat4x4LookAtLH(position,direction,up,mView);
LifeMath::Mat4x4PerspectiveFOV(outerAngle,1.0f,0.1f,range, mProj);
matrix = mView * mProj;
frustum.UpdateFrustum(matrix);
isMatrixValid = true;
}
LifeMath::float3 up;
bool isMatrixValid;
LifeMath::float4x4 matrix;
LifeMath::float4x4 mView;
LifeMath::float4x4 mProj;
float range;
LifeMath::float3 direction;
LifeMath::float3 position;
float innerAngle;
float outerAngle;
Frustum frustum;
};
}
#endif // Light_h__
+19
View File
@@ -0,0 +1,19 @@
#include "MeshManager.h"
namespace LifeGraphics
{
MeshManager::MeshManager()
{
}
MeshManager::~MeshManager()
{
}
IMesh* MeshManager::CreateBox(float sX, float sY, float sZ, bool bLockable)
{
IRenderer* render = CG::me()->GetRenderer();
LifeGraphics::Vertex::SVertexTbn vertex[24];
return 0;
}
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef MeshManager_h__
#define MeshManager_h__
#include "Singleton.h"
#include "IObjectMesh.h"
#include "render/IRenderer.h"
#include "Vertex.h"
namespace LifeGraphics
{
class MeshManager : public Singleton<MeshManager>
{
public:
MeshManager();
~MeshManager();
IMesh* CreateBox(float sX = 1.0f, float sY = 1.0f, float sZ = 1.0f, bool bLockable = false);
};
}
#endif // MeshManager_h__
+18
View File
@@ -0,0 +1,18 @@
#ifndef PassGBuffer_h__
#define PassGBuffer_h__
#include "render/IRenderer.h"
namespace LifeGraphics
{
class PassGBuffer
{
public:
PassGBuffer()
{
}
~PassGBuffer()
{
}
};
}
#endif // PassGBuffer_h__
+34
View File
@@ -0,0 +1,34 @@
#include "Plugin.h"
#include <stdexcept>
namespace LifeGraphics
{
Plugin::Plugin(const std::string& fileName)
{
g_hDLL = ::LoadLibraryA(fileName.c_str());
if(!g_hDLL)
throw std::runtime_error("Could not load library");
try
{
g_pfnGetPluginVersion = reinterpret_cast<fn_getPluginVersion>(::GetProcAddress(g_hDLL, "getPluginVersion"));
g_pfnGetEngineVersion = reinterpret_cast<fn_getEngineVersion>(::GetProcAddress(g_hDLL, "getEngineVersion"));
g_pfnRegisterPlugin = reinterpret_cast<fn_registerPlugin>(::GetProcAddress(g_hDLL, "registerPlugin"));
//g_pfnGetPluginName = reinterpret_cast<fn_getPluginName>(::GetProcAddress(g_hDLL, "getPluginName"));
if(!g_pfnGetPluginVersion || !g_pfnGetEngineVersion || !g_pfnRegisterPlugin)
throw std::runtime_error("Plugin is not valid");
}
catch(...)
{
::FreeModule(g_hDLL);
throw std::runtime_error("Plugin is not valid");
}
}
Plugin::~Plugin()
{
if(g_referenceCount<=0 && g_hDLL != NULL)
::FreeModule(g_hDLL);
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef Plugin_h__
#define Plugin_h__
#pragma once
#include "Build.h"
#include <Windows.h>
#include "render/IRenderer.h"
namespace LifeGraphics
{
class PluginServer;
class Plugin
{
public:
Plugin(const std::string& fileName);
~Plugin();
int getEngineVersion(){
return g_pfnGetEngineVersion();
}
int getPluginVersion(){
return g_pfnGetPluginVersion();
}
void registerPlugin(PluginServer& server){
return g_pfnRegisterPlugin(server);
}
/*LIFE_EXPORTS std::string getPluginName(){
return g_pfnGetPluginName();
}*/
private:
typedef int (*fn_getEngineVersion)(void);
typedef int (*fn_getPluginVersion)(void);
typedef void (*fn_registerPlugin)(LifeGraphics::PluginServer&);
HMODULE g_hDLL;
int g_referenceCount;
fn_getEngineVersion g_pfnGetEngineVersion;
fn_getPluginVersion g_pfnGetPluginVersion;
fn_registerPlugin g_pfnRegisterPlugin;
//fn_getPluginName g_pfnGetPluginName;
};
}
#endif // Plugin_h__
+46
View File
@@ -0,0 +1,46 @@
#include "PluginServer.h"
#include <memory>
namespace LifeGraphics
{
PluginServer::PluginServer()
{
}
PluginServer::~PluginServer()
{
for(RendererVector::reverse_iterator it = g_rendererCollection.rbegin();
it != g_rendererCollection.rend(); ++it)
{
delete *it;
}
for(PluginMap::reverse_iterator it = g_loadedPlugins.rbegin();
it != g_loadedPlugins.rend(); ++it)
{
delete it->second;
}
}
HRESULT PluginServer::LoadPlugin(const std::string& name)
{
if(g_loadedPlugins.find(name) == g_loadedPlugins.end())
{
Plugin* p = new Plugin(name);
p->registerPlugin(*this);
g_loadedPlugins.insert(PluginMap::value_type(name, p));
printf("%s\n", "Plugin successfully loaded!");
//std::string s = p.getPluginName();
printf(g_rendererCollection.at(0)->GetRendererName().c_str());
}
return S_OK;
}
void PluginServer::RegisterRendererPlugin(IRenderer* renderer)
{
printf("%s\n", renderer->GetRendererName().c_str());
g_rendererCollection.push_back(renderer);
}
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef PluginServer_h__
#define PluginServer_h__
#pragma once
#pragma warning (disable: 4251)
#define WIN32_LEAN_AND_MEAN
#include <vector>
#include <map>
#include "Plugin.h"
#include "render/IRenderer.h"
#include <winerror.h>
#include "Build.h"
namespace LifeGraphics
{
class LIFE_EXPORTS PluginServer
{
public:
PluginServer();
~PluginServer();
void RegisterRendererPlugin(IRenderer* renderer);
HRESULT LoadPlugin(const std::string& name);
IRenderer* GetRenderer(int index)
{
printf(g_rendererCollection.at(0)->GetRendererName().c_str());
return g_rendererCollection.at(index);
}
typedef std::vector<IRenderer*> RendererVector;
typedef std::map<std::string, Plugin*> PluginMap;
private:
RendererVector g_rendererCollection;
PluginMap g_loadedPlugins;
};
}
#endif // PluginServer_h__
+41
View File
@@ -0,0 +1,41 @@
#ifndef Rectangle2D_h__
#define Rectangle2D_h__
namespace LifeGraphics
{
class Rectangle2D
{
public:
float minX;
float minY;
float maxX;
float maxY;
Rectangle2D(float _minX, float _minY, float _maxX, float _maxY)
{
minX = _minX;
maxX = _maxX;
minY = _minY;
maxY = _maxY;
}
const float width() const
{
return maxX - minX;
}
const float height() const
{
return maxY - minY;
}
Rectangle2D()
{
minX = 0.0f;
maxX = 0.0f;
minY = 0.0f;
maxY = 0.0f;
}
~Rectangle2D()
{
}
};
}
#endif // Rectangle2D_h__
+21
View File
@@ -0,0 +1,21 @@
#ifndef RenderOperation_h__
#define RenderOperation_h__
#include "IMesh.h"
namespace LifeGraphics
{
class RenderOperation
{
public:
RenderOperation()
{
}
~RenderOperation()
{
}
IMesh* mesh;
IShader* vertexShader, pixelShader;
int submesh;
};
}
#endif // RenderOperation_h__
+10
View File
@@ -0,0 +1,10 @@
#ifndef RenderPass_h__
#define RenderPass_h__
#include "render/IRenderer.h"
#include "IScene.h"
namespace LifeGraphics
{
}
#endif // RenderPass_h__
+33
View File
@@ -0,0 +1,33 @@
#ifndef RenderQueue_h__
#define RenderQueue_h__
#include <vector>
#include <queue>
#include "IGraphicsNode.h"
namespace LifeGraphics
{
class RenderQueue
{
private:
std::queue<IGraphicsNode*> container;
public:
RenderQueue(){}
~RenderQueue(){}
int count()
{
return container.size();
}
void push(IGraphicsNode* node)
{
container.push(node);
}
void pop()
{
return container.pop();
}
IGraphicsNode* getCurrent()
{
return container.back();
}
};
}
#endif // RenderQueue_h__
+639
View File
@@ -0,0 +1,639 @@
#include "ResourceManager.h"
#include "render/IMaterial.h"
namespace LifeGraphics
{
struct VMFHEADER
{
int fileVersion;
int fileSignature;
int expPosition;
int expNormal;
int expTexcoord;
int expTangent;
int expBiNormal;
int expVertexColor;
int expSkin;
int vertexCount;
int faceCount;
int bonesCount;
int vertexSize;
};
/*void ResourceManager::getMaterial(String& path, IMaterial** material)
{
pugi::xml_document doc;
char* data;
Core::IFile* file = getFileSystem()->GetFile(path);
Core::IDataStream* stm = file->OpenRead();
data = new char[stm->length()];
stm->Read(data, stm->length());
doc.load_buffer(data, stm->length());
printf("%s\n", doc.child("LifeMaterial").attribute("Emissive").value());
stm->Close();
}*/
ResourceManager::ResourceManager()
{
lastId = 0;
lastTimeUpdated = 0.0f;
updatePeriod = 5.0f;
LifeCore::RootFolder* root = new LifeCore::RootFolder();
root->Name = String(_text("root"));
fileSystem = new LifeCore::IFileSystem(root);
fileSystem->StorageName = String(_text("root"));
shaderDefines[EF_LIGHTING] = "DEF_LIGHTING";
shaderDefines[EF_NORMAL_MAP] = "DEF_NORMAL_MAP";
shaderDefines[EF_PARALLAX_MAP] = "DEF_PARALLAX_MAP";
shaderDefines[EF_ENVIRONMENT_MAP] = "DEF_ENVIRONMENT_MAP";
shaderDefines[EF_SPECULAR_MAP] = "DEF_SPECULAR_MAP";
shaderDefines[EF_EMISSIVE_MAP] = "DEF_EMISSIVE_MAP";
shaderDefines[EF_G_BUFFER_PREPASS] = "DEF_G_PREPASS";
shaderDefines[EF_SKINNING] = "DEF_SKINNING";
shaderDefines[EF_LINEAR_DEPTH] = "DEF_LINEAR_DEPTH";
shaderDefines[EF_ALPHA_TEST] = "DEF_ALPHA_TEST";
shaderCompiler = new ShaderGraphCompilerHLSL();
shaderFactory = IShaderGraphNodeFactory::me();
IShaderFactorySource::Register(shaderFactory);
IShaderGraph* defaultGraph = new IShaderGraph(shaderFactory);
IShaderGraphNode* mat = defaultGraph->AddNode("Material");
IShaderGraphNode* mat_diffuse = defaultGraph->AddNode("ConstFloat4");
IShaderGraphNodePort* port_diffuse = mat->GetInputPortByName("Diffuse");
port_diffuse->MakeLink(port_diffuse, mat_diffuse->GetOutputPortByID(0));
LifeCore::IProperty* diffuse;
if(mat_diffuse->GetPropertyByAttribute("Name", "Value", &diffuse)){
diffuse->Set(LifeMath::float4(0,1,0,1));
}
defaultMaterial = new IMaterial(defaultGraph, shaderCompiler);
}
ResourceManager::~ResourceManager()
{
}
void ResourceManager::CollectGarbage(float dt)
{
}
void ResourceManager::ReleaseResources()
{
shaderDefines.clear();
for(UINT i = 0; i< contentProviders.size(); i++)
{
delete contentProviders[i];
}
delete fileSystem;
textureCache.Release();
vsCache.Release();
psCache.Release();
}
void ResourceManager::initialize()
{
}
long ResourceManager::NextID()
{
return lastId++;
}
void ResourceManager::SetCentralDirectory(const String& dir)
{
centralDir = dir;
LifeCore::IContentProvider* fsProvider = new LifeCore::IFSContentProvider(dir);
MountContentProvider(fsProvider, String(_text("root")));
}
IShader* ResourceManager::getShader(IMaterial* material, int adFlags, SHADER_TYPE type)
{
assert(false && "getShader is obsolete!\n");
/*int flags = adFlags;
if(material->normalMapping)
flags |= EF_NORMAL_MAP;
if(material->lighting)
flags |= EF_LIGHTING;
if(material->environmentReflection)
flags |= EF_ENVIRONMENT_MAP;
if(material->bSpecularMapping)
flags |= EF_SPECULAR_MAP;
if(material->AlphaTest)
flags |= EF_ALPHA_TEST;
if(type == ST_PS)
return GetPixelShader(flags);
else
return GetVertexShader(flags);*/
return nullptr;
}
IMaterial* ResourceManager::getDefaultMaterial()
{
return defaultMaterial;
assert(false && "getDefaultMaterial is obsolete!\n");
/*if(!DefaultMaterial)
{
DefaultMaterial = new IMaterial();
memset(DefaultMaterial,0, sizeof(IMaterial));
DefaultMaterial->castShadows = false;
DefaultMaterial->diffuseMap = GetTexture(AS_STRING("root/Data/Textures/NoTex.dds"));
setupMaterialShaders(EF_LIGHTING, DefaultMaterial);
}*/
}
LifeCore::IFileSystem* ResourceManager::getFileSystem()
{
return fileSystem;
}
void ResourceManager::MountContentProvider(LifeCore::IContentProvider* prov, const String& mountPoint)
{
contentProviders.push_back(prov);
fileSystem->GetRootFolder()->AddFolder(prov->getFileSystem()->GetRootFolder());
LifeCore::CLog::me()->Write(String(_text("Mount point is not used! SHOULD BE FIXED!\nResourceManager::MountContentProvider at")));
LifeCore::CLog::me()->Write(mountPoint.c_str());
}
texture_ptr ResourceManager::GetTexture(const String& path)
{
if(path == STR(""))
return nullptr;
String name = GetFileName(path, _text("/"));
texture_ptr ptr;
if(textureCache.GetResource(name, ptr))
return ptr.ptr();
else
{
LifeCore::IFile* texFile;
ResourceManager::me()->getFileSystem()->GetFile(path, &texFile);
LifeCore::IDataStreamPtr stm = texFile->OpenRead();
ITexture2D* texture = CG::me()->GetRenderer()->LoadTexture2D(stm);
texture->Name = name;
texture_ptr texPtr(texture);
textureCache.push_back(texPtr);
return texPtr;
}
}
void ResourceManager::ReadBitmap(String& path, void** pOut, IBitmapInfo** info)
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(path, &file);
LifeCore::IDataStreamPtr stm = file->OpenRead();
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
//read the bitmap file header
stm->Read(&bitmapFileHeader, sizeof(BITMAPFILEHEADER));
//verify that this is a bmp file by check bitmap id
if (bitmapFileHeader.bfType !=0x4D42)
{
return;
}
//read the bitmap info header
stm->Read(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER));
//move file point to the begging of bitmap data
stm->Seek(bitmapFileHeader.bfOffBits);
//allocate enough memory for the bitmap image data
char* data = new char[bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * bitmapInfoHeader.biBitCount / 8];
//read in the bitmap image data
stm->Read(data, bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * bitmapInfoHeader.biBitCount / 8);
IBitmapInfo* i = new IBitmapInfo();
i->Width = bitmapInfoHeader.biWidth;
i->Height = bitmapInfoHeader.biHeight;
i->Bpp = bitmapInfoHeader.biBitCount / 8;
*(pOut) = data;
*(info) = i;
}
IShader* ResourceManager::GetPixelShader(int compileFlags)
{
String shaderPath(_text("Core.psh"));
char name[16];
_itoa_s(compileFlags, name, 10);
String sName(name);
//create defines list
std::vector<IMacroDefine> defines;
for(std::map<EFFECT_FLAGS, std::string>::iterator it = shaderDefines.begin(); it != shaderDefines.end(); it++)
{
if((compileFlags & it->first) != 0)
{
defines.push_back(IMacroDefine(it->second));
}
}
resource_ptr<IShader> ptr;
if(psCache.GetResource(sName, ptr))
return ptr.ptr();
else
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + shaderPath, &file);
LifeCore::IDataStreamPtr stm = file->OpenRead();
IShader* s = CG::me()->GetRenderer()->CompilePixelShader(stm, &defines);
ptr.resetPtr(s);
ptr->Name = sName;
psCache.push_back(ptr);
return ptr.ptr();
}
defines.clear();
}
IShader* ResourceManager::GetVertexShader(int compileFlags)
{
String shaderPath(_text("Core.vsh"));
char name[16];
_itoa_s(compileFlags, name, 10);
String sName(name);
//create defines list
std::vector<IMacroDefine> defines;
for(std::map<EFFECT_FLAGS, std::string>::iterator it = shaderDefines.begin(); it != shaderDefines.end(); it++)
{
if((compileFlags & it->first) != 0)
{
defines.push_back(IMacroDefine(it->second));
}
}
resource_ptr<IShader> ptr;
if(vsCache.GetResource(sName, ptr))
return ptr.ptr();
else
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + shaderPath, &file);
LifeCore::IDataStreamPtr stm = file->OpenRead();
IShader* s = CG::me()->GetRenderer()->CompileVertexShader(stm, &defines);
ptr.resetPtr(s);
ptr->Name = sName;
vsCache.push_back(ptr);
return ptr.ptr();
}
defines.clear();
}
IMesh* ResourceManager::GetMesh(const String& path)
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(path, &file);
printf("Trololo %s\n", file->FileName.c_str());
LifeCore::IDataStreamPtr stm = file->OpenRead();
printf("Trololo %i\n", stm->Length());
VMFHEADER header;
stm->Read(&header, sizeof(VMFHEADER));
char* vertexData = new char[header.vertexCount * header.vertexSize];
stm->Read(vertexData, header.vertexCount * header.vertexSize);
bool computeBoundingBox = true;
LifeCore::BoundingBox3D bbox;
if(computeBoundingBox)
{
float* ptr = reinterpret_cast<float*>(vertexData);
float minX = ptr[0];
float minY = ptr[1];
float minZ = ptr[2];
float maxX = minX;
float maxY = minY;
float maxZ = minZ;
for(int i = 0; i< header.vertexCount; i++)
{
ptr = reinterpret_cast<float*>(vertexData + (header.vertexSize * i));
if(minX > ptr[0])
minX = ptr[0];
if(minY > ptr[1])
minY = ptr[1];
if(minZ > ptr[2])
minZ = ptr[2];
if(maxX < ptr[0])
maxX = ptr[0];
if(maxY < ptr[1])
maxY = ptr[1];
if(maxZ < ptr[2])
maxZ = ptr[2];
}
bbox.resize(LifeMath::float3(minX, minY, minZ), LifeMath::float3(maxX, maxY, maxZ));
}
int submeshCount= 0;
stm->Read(&submeshCount, 4);
int* submeshData = new int[2*submeshCount];
stm->Read(submeshData, 2*submeshCount*4);
//IShader* vs = GetVertexShader(EFFECT_FLAGS::EF_LIGHTING);
//IShader* ps = GetPixelShader(EFFECT_FLAGS::EF_LIGHTING);
int isShortIndices = 0;
stm->Read(&isShortIndices, 4);
int indexSize = isShortIndices == 1 ? 2 : 4;
char* indexData = new char[header.faceCount * 3 * indexSize];
stm->Read(indexData, header.faceCount * 3 * indexSize);
Skeleton sk;
if(header.expSkin)
{
sk.BonesCount = header.bonesCount;
//add system root bone
Bone* b = new Bone(-1, "Root", -2);
QuatIdentity(b->LocalTransform.Rotation);
b->LocalTransform.Translation = LifeMath::float3(0.0f,0.0f,0.0f);
QuatIdentity(b->BaseTransform.Rotation);
b->BaseTransform.Translation = LifeMath::float3(0.0f,0.0f,0.0f);
Mat4x4Identity(&b->TransformMatrix);
Mat4x4Identity(&b->AbsoluteMatrix);
sk.AddBone(b);
//read bones hierarchy
for (int j = 0; j < header.bonesCount; j++)
{
int bId;
stm->Read(&bId, sizeof(int));
int pId;
stm->Read(&pId, sizeof(int));
char b_nChars[33];
stm->Read(b_nChars, 33);
std::string bName = std::string(b_nChars);
Bone* b = new Bone(bId, bName, pId);
sk.AddBone(b);
}
sk.rebuildLinks();
for (int j = 0; j < header.bonesCount; j++)
{
int bId;
stm->Read(&bId, sizeof(int));
LifeMath::float3 pos;
stm->Read(&pos, sizeof(LifeMath::float3));
LifeMath::Quaternion rot;
stm->Read(&rot, sizeof(LifeMath::Quaternion));
BoneTransform transform;
transform.Translation = pos;
transform.Rotation = rot;
transform.boneId = bId;
Bone* cBone = sk.GetBone(bId);
cBone->BaseTransform = transform;
if (bId == 0)
{
cBone->LocalTransform = transform;
cBone->InitialTransform = transform;
cBone->BaseTransform = transform;
}
else
{
BoneTransform pt = cBone->Parent->BaseTransform;
//LifeMath::float4x4 mParent = Matrix4x4.Invert(Matrix4x4.RotationQuaternion(pt.Rotation) * Matrix4x4.Translation(pt.Translation));
LifeMath::float4x4 mParent = pt.GetMatrixInvert();
LifeMath::float4x4 mBone = transform.GetMatrix();
LifeMath::float4x4 mabs = mBone * mParent;
LifeMath::float3 pos2, scl2;
LifeMath::Quaternion rot2;
LifeMath::Mat4x4Decompose(mabs, pos2, scl2, rot2);
BoneTransform bt;
bt.Translation = pos2;
bt.Rotation = rot2;
bt.boneId = bId;
//cBone->LocalTransform = bt;
cBone->LocalTransform = bt;
cBone->InitialTransform = transform;
cBone->BaseTransform = transform;
}
}
}
texture_ptr defaultTex = GetTexture("root/Data/Textures/basic_floor_s.dds");
texture_ptr defaultNorm = GetTexture("root/Data/Textures/basic_floor_s_ddn.dds");
GeometrySubset* subsets = new GeometrySubset[submeshCount];
for(int i = 0; i< submeshCount; i++)
{
subsets[i].Offset = submeshData[i * 2 + 0];
subsets[i].Length = submeshData[i * 2 + 1];
printf("Has skin: %i\n", header.expSkin);
/*if(header.expSkin)
setupMaterialShaders(EF_LIGHTING | EF_SKINNING, &subsets[i].material);
else
setupMaterialShaders(EF_LIGHTING, &subsets[i].material);
subsets[i].material.diffuseMap = defaultTex;
subsets[i].material.normalMap = defaultNorm;*/
}
IVertexBuffer* vb = CG::me()->GetRenderer()->CreateVertexBuffer(header.vertexCount * header.vertexSize, vertexData, header.vertexSize);
delete[] vertexData;
IIndexBuffer* ib = CG::me()->GetRenderer()->CreateIndexBuffer(header.faceCount * 3 * indexSize,indexData, isShortIndices);
delete[] indexData;
delete[] submeshData;
IInputElement* elements;
int numElements = 5;
if(header.expSkin)
{
numElements = 7;
elements = new IInputElement[numElements];
elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0);
elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[5] = IInputElement("BLENDINDICES", 0, 56, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0);
elements[6] = IInputElement("BLENDWEIGHT", 0, 72, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0);
}
else
{
elements = new IInputElement[numElements];
elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0);
elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
}
IShader* ds;
if(header.expSkin)
ds = GetVertexShader(EF_LIGHTING | EF_SKINNING);
else
ds = GetVertexShader(EF_LIGHTING);
IInputLayout* layout = CG::me()->GetRenderer()->CreateInputLayout(elements, numElements, ds);
delete[] elements;
IMesh* mesh = new IMesh(vb, ib, subsets, layout, header.expSkin, bbox, file->FileName);
mesh->Id = NextID();
mesh->subsetCount = submeshCount;
if(header.expSkin)
{
mesh->skin.bonesCount = header.bonesCount;
sk.UpdateTransform();
mesh->skin.skeleton = sk;
mesh->skin.controller.skeleton = &mesh->skin.skeleton;
}
return mesh;
}
void ResourceManager::setupMaterialShaders(int shaderFlags, IMaterial* material)
{
//printf("OMGNAH");
// material->pixelShader = GetPixelShader(shaderFlags);
// material->vertexShader = GetVertexShader(shaderFlags);
assert(false && "setupMaterialShaders is obsolete!");
//material->g_buffer_pass_ps = GetPixelShader(shaderFlags | EF_G_BUFFER_PREPASS);
//material->g_buffer_pass_vs = GetVertexShader(shaderFlags | EF_G_BUFFER_PREPASS);
}
Light* ResourceManager::CreatePointLight(const LifeMath::float3& position, float range)
{
Light* l = new Light(LT_POINT);
l->getTransform()->SetPosition(position);
l->setRange(range);
l->Id = NextID();
return l;
}
Light* ResourceManager::CreateDirectionalLight(const LifeMath::float3& direction)
{
Light* l = new Light(LT_DIRECTIONAL);
l->setDirection(direction);
l->Id = NextID();
return l;
}
Light* ResourceManager::CreateSpotLight(const LifeMath::float3& position, const LifeMath::float3& direction, float range, float innerAngle, float outerAngle)
{
Light* l = new Light(LT_SPOT);
l->getTransform()->SetPosition(position);
l->setRange(range);
l->setInnerAngle(innerAngle);
l->setOuterAngle(outerAngle);
l->setDirection(direction);
l->Id = NextID();
return l;
}
IShader* ResourceManager::CompileUserShaderPS(const String& path)
{
LifeCore::IFile* file;
if(SC_OK == ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + path, &file))
{
//CLog::me()->
LifeCore::IDataStreamPtr stm = file->OpenRead();
IShader* s = CG::me()->GetRenderer()->CompilePixelShader(stm);
s->Name = GetFileName(path, String(_text("/")));
return s;
}
return 0;
}
IShader* ResourceManager::CompileUserShaderVS(const String& path)
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + path, &file);
LifeCore::IDataStreamPtr stm = file->OpenRead();
IShader* s = CG::me()->GetRenderer()->CompileVertexShader(stm);
s->Name = GetFileName(path, String(_text("/")));
return s;
}
IShader* ResourceManager::CompileUserShaderPS(const char* pData, int length)
{
IShader* s = CG::me()->GetRenderer()->CompilePixelShader(pData, length);
s->Name = STR("system_ps");
return s;
}
IShader* ResourceManager::CompileUserShaderVS(const char* pData, int length)
{
IShader* s = CG::me()->GetRenderer()->CompileVertexShader(pData, length);
s->Name = STR("system_vs");
return s;
}
AnimationTrack* ResourceManager::LoadAnimatrionTrack(String& path)
{
LifeCore::IFile* file;
ResourceManager::me()->getFileSystem()->GetFile(path, &file);
LifeCore::IDataStreamPtr stm = file->OpenRead();
float sampleRate;
int framesCount, BonesCount;
stm->Read(&BonesCount, sizeof(int));
stm->Read(&framesCount, sizeof(int));
AnimationTrack* animationTrack = new AnimationTrack(framesCount);
animationTrack->Name = GetFileName(path, String(_text("/")));
int sr;
stm->Read(&sr, sizeof(int));
sampleRate = (float)sr;
//add all frames
for (int j = 0; j < framesCount; j++)
{
AnimationFrame frame((float)j / sampleRate);
frame.name = j;
//read bones keys
for (int i = 0; i < BonesCount; i++)
{
int bId;
stm->Read(&bId, sizeof(int));
BoneTransform transform;
stm->Read(&transform.Translation, sizeof(LifeMath::float3));
stm->Read(&transform.Rotation, sizeof(LifeMath::Quaternion));
transform.boneId = bId;
frame.addBoneTransform(transform);
}
animationTrack->setFrame(frame, j);
}
animationTrack->TrackTime = (float)(framesCount-1) / sampleRate;
return animationTrack;
}
}
+104
View File
@@ -0,0 +1,104 @@
#ifndef RESOURCE_MANAGER_H__
#define RESOURCE_MANAGER_H__
#include "LifeDebug.h"
#include "Singleton.h"
#include "LString.h"
#include "vfs/IFileSystem.h"
#include "vfs/RootFolder.h"
#include "render/ITexture2D.h"
#include "IMesh.h"
#include "vfs/fs_win/IFSContentProvider.h"
#include <vector>
#include <map>
#include "CG.h"
#include "Types.h"
#include "TypesVideo.h"
#include "Light.h"
#include "IResourceCollection.h"
#include "Skeleton.h"
#include "AnimationTrack.h"
#include "pugixml.hpp"
#include "shaders/ShaderGraphCompilerHLSL.h"
#include "shaders/IShaderGraphNodeFactory.h"
#include "shaders/IShaderFactorySource.h"
namespace LifeGraphics
{
class IMaterial;
struct IBitmapInfo
{
int Width;
int Height;
int Bpp;
};
enum EFFECT_FLAGS
{
EF_NONE = 0,
EF_LIGHTING = 1 << 0,
EF_NORMAL_MAP = 1 << 1,
EF_PARALLAX_MAP = 1 << 2,
EF_ENVIRONMENT_MAP = 1 << 3,
EF_SPECULAR_MAP = 1 << 4,
EF_EMISSIVE_MAP = 1 << 5,
EF_G_BUFFER_PREPASS = 1 << 6,
EF_SKINNING = 1 << 7,
EF_LINEAR_DEPTH = 1 << 8,
EF_ALPHA_TEST = 1 << 9
};
class ResourceManager;
class ResourceManager : public Singleton<ResourceManager>
{
public:
ResourceManager();
~ResourceManager();
void SetCentralDirectory(const String& dir);
void initialize();
LifeCore::IFileSystem* getFileSystem();
void MountContentProvider(LifeCore::IContentProvider* prov, const String& mountPoint);
texture_ptr GetTexture(const String& path);
IShader* GetPixelShader(int flags);
IShader* GetVertexShader(int flags);
IMesh* GetMesh(const String& path);
Light* CreatePointLight(const LifeMath::float3& position, float range);
Light* CreateDirectionalLight(const LifeMath::float3& direction);
void setupMaterialShaders(int shaderFlags, IMaterial* material);
Light* CreateSpotLight(const LifeMath::float3& position, const LifeMath::float3& direction, float range, float innerAngle, float outerAngle);
IShader* CompileUserShaderPS(const String& path);
IShader* CompileUserShaderVS(const String& path);
IShader* CompileUserShaderPS(const char* pData, int length);
IShader* CompileUserShaderVS(const char* pData, int length);
AnimationTrack* LoadAnimatrionTrack(String& path);
void ReleaseResources();
void ReadBitmap(String& path, void** pOut, IBitmapInfo** info);
void CollectGarbage(float dt);
IMaterial* getDefaultMaterial();
void getMaterial(String& path, IMaterial** material);
IShader* getShader(IMaterial* material, int adFlags, SHADER_TYPE type);
private:
IShaderGraphCompiler* shaderCompiler;
IShaderGraphNodeFactory* shaderFactory;
IMaterial* defaultMaterial;
float lastTimeUpdated;
float updatePeriod;
String centralDir;
LifeCore::IFileSystem* fileSystem;
IResourceCollection<ITexture2D> textureCache;
IResourceCollection<IShader> vsCache;
IResourceCollection<IShader> psCache;
std::map<EFFECT_FLAGS, std::string> shaderDefines;
std::vector<LifeCore::IContentProvider*> contentProviders;
long lastId;
long NextID();
};
}
#endif
+206
View File
@@ -0,0 +1,206 @@
#ifndef ShadowMapManager_h__
#define ShadowMapManager_h__
#include "render/IRenderer.h"
#include <vector>
#include "math/Vector4D.h"
#include "math/Vector2D.h"
#include "Rectangle2D.h"
#include "math/Matrix4x4.h"
#include "Light.h"
#include "Globals.h"
#include <float.h>
namespace LifeGraphics
{
struct SHADOW_DATA
{
LifeMath::float4 uvOffset_uvScale;
LifeMath::float4 shadowMapTexelSize_dummy;
};
class ShadowMapManager
{
private:
IRenderer* renderer;
int shadowMapResolution;
std::vector<LifeMath::float4> texRegions;
std::vector<LifeMath::Rect2i> viewRegions;
ITexture2D* depthBuffer;
ITexture2D* shadowBuffer;
IBlendState* restoreBlendState;
LifeMath::float4x4 lightMatrices[4];
int curLightIndex;
IBlendState* shadowBlendState;
void ComputeDepthRegionDistribution(int lightCount)
{
texRegions.clear();
viewRegions.clear();
printf("SHOULD FIX RECTANGLES!!!!!!!!!!!!!!!!!!!!! NOT COORD! WIDTH!!!!!!!!!!!!!!! ComputeDepthRegionDistribution\n");
switch (lightCount)
{
case 1:
//----------|
//| |
//| 1 |
//| |
//| |
//----------|
texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 1.0f));
viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution));
break;
case 2:
//----------|
//| 1 |
//| |
//-----------
//| |
//| 2 |
//----------|
/*texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f));
viewRegions.push_back(Rectangle2D(0.0f, 0.0f, shadowMapResolution2, shadowMapResolution2 / 2));
texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f));
viewRegions.push_back(Rectangle2D(0.0f, shadowMapResolution2 / 2, shadowMapResolution2, shadowMapResolution2 / 2));*/
texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution / 2));
texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution, shadowMapResolution));
break;
case 3:
texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution / 2));
texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution));
texRegions.push_back(LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution, shadowMapResolution));
break;
case 4:
texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution / 2, shadowMapResolution / 2));
texRegions.push_back(LifeMath::float4(0.5f, 0.0f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, 0, shadowMapResolution / 2, shadowMapResolution / 2));
texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2));
texRegions.push_back(LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f));
viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2));
break;
}
}
public:
IDepthStencilState* depthState;
IShader* rtdPs;
IShader* rtdPsAT;
IShader* rtdCubePs;
IShader* rtdCubePsAT;
ITextureSampler* samplerPCF;
ShadowMapManager()
:shadowMapResolution(1024)
{
for(int i = 0; i<4; i++)
{
texRegions.push_back(LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f));
}
}
~ShadowMapManager()
{
SAFE_DELETE(depthBuffer);
SAFE_DELETE(rtdPs);
SAFE_DELETE(shadowBlendState);
SAFE_DELETE(depthState);
}
SHADOW_DATA getShadowInfo(int id)
{
SHADOW_DATA data;
data.uvOffset_uvScale = texRegions[id];
data.shadowMapTexelSize_dummy.X = (float)shadowMapResolution;
data.shadowMapTexelSize_dummy.Y = (float)shadowMapResolution;
return data;
}
void beginShadowRendering(int lightCount)
{
renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution));
curLightIndex = 0;
if (lightCount > 0)
{
if (lightCount > 4)
lightCount = 4;
ComputeDepthRegionDistribution(lightCount);
}
renderer->UnbindResourcesPS();
renderer->SetTargets(shadowBuffer, depthBuffer);
LifeMath::float4 color = LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f);
renderer->ClearDepthStencil(depthBuffer, 1.0f, 0);
//renderer->ClearBuffers(CF_DEPTH_BUFFER, 0x00000000, 1.0f, 0);
// renderer->ClearRenderTarget(shadowBuffer, &color);
//renderer->SetBlendState(shadowBlendState);
renderer->SetDepthStencilState(depthState);
renderer->SetPSTextureSampler(samplerPCF, 2);
//renderer->SetPixelShader(rtdPs);
}
void beginLightRender(Light* light)
{
lightMatrices[curLightIndex] = light->getMatrix();
// renderer->ClearBuffers(CF_DEPTH_BUFFER, 0x00000000, 1.0f, 0);
renderer->SetViewport(viewRegions[curLightIndex]);
//renderer->SetViewport(viewRegions[curLightIndex], 0, 100000000.0f);
}
void endLightRender()
{
curLightIndex++;
}
ITexture2D* getShadowMap()
{
return shadowBuffer;
}
void Init(IRenderer* _renderer)
{
renderer = _renderer;
#define MAX_LINEAR_DEPTH 1.e30f
/* ComparisonFunc = LESS;
Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
AddressU = Border;
AddressV = Border;
BorderColor = float4(MAX_LINEAR_DEPTH, 0, 0, 0);*/
ISamplerDescription desc(Border, Border, Border, ComparisonMinMagLinearMipPoint, COMPARISON_LESS);
samplerPCF = renderer->CreateTextureSampler(&desc);
depthBuffer = CG::me()->GetRenderer()->CreateDepthTarget(shadowMapResolution, shadowMapResolution, FORMAT_R32_TYPELESS);
shadowBuffer = CG::me()->GetRenderer()->CreateRenderTarget(shadowMapResolution, shadowMapResolution, FORMAT_R32_FLOAT);
rtdPs = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF.psh")));
rtdPsAT = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_AT.psh")));
rtdCubePs = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_CUBE.psh")));
rtdCubePsAT = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_AT.psh")));
shadowBlendState = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ZERO, BLEND_ONE, 0);
restoreBlendState = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ZERO, 1 | 2 | 4 | 8);
depthState = renderer->CreateDSState(true, true, COMPARISON_LESS);
}
};
}
#endif // ShadowMapManager_h__
+117
View File
@@ -0,0 +1,117 @@
#ifndef Skeleton_h__
#define Skeleton_h__
#include <map>
#include "Bone.h"
#include "AnimationTrack.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
namespace LifeGraphics
{
class Skeleton
{
public:
int maxBoneID;
int BonesCount;
std::map<int, Bone*> Bones;
Skeleton()
:maxBoneID(0)
{
}
Bone* AddBone(Bone* bone)
{
Bones[bone->ID] = bone;
return bone;
}
void rebuildLinks()
{
//clear all dependencies
for(std::map<int, Bone*>::iterator it = Bones.begin(); it != Bones.end(); it++)
{
it->second->clearChilds();
it->second->Parent = 0;
}
//rebuild hierarchy links
for(std::map<int, Bone*>::iterator it = Bones.begin(); it != Bones.end(); it++)
{
if(it->second->ParentId != -2)
{
it->second->Parent = GetBone(it->second->ParentId);
it->second->Parent->AddChild(it->second);
}
}
}
void UpdateTransform()
{
for (int i = 0; i < BonesCount; i++)
{
LifeMath::float4x4 BoneLocal;
LifeMath::float4x4 BoneBase;
Bone* bone = Bones[i];
BoneLocal = bone->LocalTransform.GetMatrix();
BoneBase = bone->BaseTransform.GetMatrix();
BoneBase = Mat4x4Invert(&BoneBase);
//BoneLocal = BoneBase * BoneLocal;
if (bone->Parent)
{
//bone->TransformMatrix = BoneLocal * bone->Parent->AbsoluteMatrix;
bone->TransformMatrix = BoneLocal * bone->Parent->TransformMatrix;
}
else
{
bone->TransformMatrix = BoneLocal;
}
//bone->AbsoluteMatrix = BoneBase * bone->TransformMatrix;
bone->AbsoluteMatrix = BoneBase* bone->TransformMatrix;
bone->Update();
}
}
LifeMath::float4x4 BuildMatrix(BoneTransform* transform)
{
LifeMath::float4x4 rot;
LifeMath::float4x4 trans;
Mat4x4RotationQuaternion(transform->Rotation, rot);
Mat4x4Translation(transform->Translation, trans);
return rot*trans;
}
void GetMatrices(int* boneIndices, int indexCount, LifeMath::float4x4* result)
{
for (int i = 0; i < indexCount; i++)
result[i] = GetBone(boneIndices[i])->AbsoluteMatrix;
}
void GetMatrices(LifeMath::float4x4* result)
{
for (int i = 0; i < BonesCount; i++)
result[i] = GetBone(i)->AbsoluteMatrix;
}
Bone* GetBone(int boneID)
{
return Bones[boneID];
}
Bone* GetBone(String& name)
{
for(std::map<int, Bone*>::iterator it = Bones.begin(); it != Bones.end(); it++)
{
if (it->second->BoneName == name)
return it->second;
}
}
};
}
#endif // Skeleton_h__
+23
View File
@@ -0,0 +1,23 @@
#ifndef SkinInfo_h__
#define SkinInfo_h__
#include "Skeleton.h"
#include "AnimationController.h"
namespace LifeGraphics
{
class SkinInfo
{
public:
Skeleton skeleton;
AnimationController controller;
int bonesCount;
SkinInfo()
:bonesCount(0)
{
}
~SkinInfo()
{
}
};
}
#endif // SkinInfo_h__
+397
View File
@@ -0,0 +1,397 @@
#ifndef Sky_h__
#define Sky_h__
#include "Globals.h"
#include "DayTime.h"
#include "math/LifeMath.h"
namespace LifeGraphics
{
struct SkyVertex
{
LifeMath::float3 Position;
LifeMath::float2 Texcoord;
SkyVertex()
{
}
SkyVertex(LifeMath::float3& _pos, LifeMath::float2& _tex)
{
Position = _pos;
Texcoord = _tex;
}
};
struct cbRenderData
{
LifeMath::float4x4 View;
LifeMath::float4x4 Proj;
LifeMath::float4x4 ViewProj;
LifeMath::float3 SunDirection;
float dummy;
};
class Sky
{
private:
int DomeN;
int DVSize;
int DISize;
int MrlTexSize;
int MrlTexSizeHalf;
LifeMath::float3 SunrizeDirection;
LifeMath::float3 ZenithDirection;
LifeMath::float3 waveLengths;
LifeMath::float3 invWaveLengths;
LifeMath::float3 waveLengthsMie;
IVertexBuffer* skyVb;
IIndexBuffer* skyIb;
IShader* VS_Render;
IShader* VS_Update;
IShader* PS_Render;
IShader* PS_Update;
IConstantBuffer* cbUpdate;
IConstantBuffer* cbRender;
ITexture2D* skyDepth;
IInputLayout* vertexLayout;
DayTime Time;
DayTime SunsetTime;
DayTime SunrizeTime;
DayTime MidDayTime;
DayTime MidNightTime;
DayTime DayLength;
DayTime NightLength;
DayTime TimeStep;
int DayPhase;
float fExposure;
float updateTimeElapsed;
float StarsIntensity;
float updatePeriod;
bool ShouldUpdateData;
IDepthStencilState* dsZEnable;
IDepthStencilState* dsZDisable;
void RecomputeData()
{
SunrizeDirection = LifeMath::float3(-1,0,0);
ZenithDirection = LifeMath::float3(0,1,0);
DayLength = SunsetTime - SunrizeTime;
NightLength = SunrizeTime - SunsetTime;
MidNightTime = SunsetTime + (NightLength / 2);
MidDayTime = SunrizeTime + (DayLength / 2);
if (Time >= SunrizeTime && Time <= MidDayTime)
DayPhase = 0;
else if (Time >= MidDayTime && Time <= SunsetTime)
DayPhase = 1;
else if (MidNightTime - SunsetTime >= Time - SunsetTime)
DayPhase = 2;
else
DayPhase = 3;
float lamt = 0;
switch (DayPhase)
{
case 0:
lamt = (float)(Time - SunrizeTime).ToSeconds()
/ (float)(MidDayTime - SunrizeTime).ToSeconds();
SunDirection = Vec3Lerp(SunrizeDirection, ZenithDirection, lamt);
LifeMath::Vec3Normalize(&SunDirection);
StarsIntensity = 1.0f - lamt;
break;
case 1:
lamt = (float)(Time - MidDayTime).ToSeconds()
/ (float)(SunsetTime - MidDayTime).ToSeconds();
SunDirection = Vec3Lerp(ZenithDirection, -SunrizeDirection, lamt);
LifeMath::Vec3Normalize(&SunDirection);
StarsIntensity = lamt;
break;
case 2:
lamt = (float)(Time - SunsetTime).ToSeconds()
/ (float)(MidNightTime - SunsetTime).ToSeconds();
SunDirection = Vec3Lerp(-SunrizeDirection, -ZenithDirection, lamt);
LifeMath::Vec3Normalize(&SunDirection);
StarsIntensity = 1.0f;
break;
case 3:
lamt = (float)(Time - MidNightTime).ToSeconds()
/ (float)(SunrizeTime - MidNightTime).ToSeconds();
SunDirection = Vec3Lerp(-ZenithDirection, SunrizeDirection, lamt);
LifeMath::Vec3Normalize(&SunDirection);
StarsIntensity = 1.0f;
break;
}
StarsIntensity = pow(StarsIntensity,10);
invWaveLengths.X = 1.0f / pow(waveLengths.X, 4.0f);
invWaveLengths.Y = 1.0f / pow(waveLengths.Y, 4.0f);
invWaveLengths.Z = 1.0f / pow(waveLengths.Z, 4.0f);
waveLengthsMie.X = pow(waveLengths.X, -0.84f);
waveLengthsMie.Y = pow(waveLengths.Y, -0.84f);
waveLengthsMie.Z = pow(waveLengths.Z, -0.84f);
}
void GenerateDome()
{
int Latitude = DomeN / 2;
int Longitude = DomeN;
DVSize = Longitude * Latitude;
DISize = (Longitude - 1) * (Latitude - 1) * 2;
DVSize *= 2;
DISize *= 2;
IInputElement skyElements[] =
{
IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0),
IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0),
};
vertexLayout = CG::me()->GetRenderer()->CreateInputLayout(skyElements, 2, VS_Render);
SkyVertex* domeVerts = new SkyVertex[DVSize];
// Fill Vertex Buffer
int DomeIndex = 0;
for (int i = 0; i < Longitude; i++)
{
float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.141592f / 180.0f;
for (int j = 0; j < Latitude; j++)
{
float MoveY = 3.1415f * (float)j / (float)(Latitude - 1);
domeVerts[DomeIndex] = SkyVertex();
domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY));
domeVerts[DomeIndex].Position.Y = cos(MoveXZ);
domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY));
domeVerts[DomeIndex].Position *= 10.0f;
domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude;
domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude;
DomeIndex++;
}
}
for (int i = 0; i < Longitude; i++)
{
float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.1415f / 180.0f;
for (int j = 0; j < Latitude; j++)
{
float MoveY = (3.1415f * 2.0f) - (3.1415f * (float)j / (float)(Latitude - 1));
domeVerts[DomeIndex] = SkyVertex();
domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY));
domeVerts[DomeIndex].Position.Y = cos(MoveXZ);
domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY));
domeVerts[DomeIndex].Position *= 10.0f;
domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude;
domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude;
DomeIndex++;
}
}
// Fill index buffer
USHORT* ib = new USHORT[DISize * 3];
int index = 0;
for (USHORT i = 0; i < Longitude - 1; i++)
{
for (short j = 0; j < Latitude - 1; j++)
{
ib[index++] = (USHORT)(i * Latitude + j);
ib[index++] = (USHORT)((i + 1) * Latitude + j);
ib[index++] = (USHORT)((i + 1) * Latitude + j + 1);
ib[index++] = (USHORT)((i + 1) * Latitude + j + 1);
ib[index++] = (USHORT)(i * Latitude + j + 1);
ib[index++] = (USHORT)(i * Latitude + j);
}
}
USHORT Offset = (USHORT)(Latitude * Longitude);
for (USHORT i = 0; i < Longitude - 1; i++)
{
for (USHORT j = 0; j < Latitude - 1; j++)
{
ib[index++] = (USHORT)(Offset + i * Latitude + j);
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1);
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j);
ib[index++] = (USHORT)(Offset + i * Latitude + j + 1);
ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1);
ib[index++] = (USHORT)(Offset + i * Latitude + j);
}
}
skyIb = CG::me()->GetRenderer()->CreateIndexBuffer(DISize * 3 * sizeof(USHORT), ib, TRUE);
skyVb = CG::me()->GetRenderer()->CreateVertexBuffer(DVSize * sizeof(SkyVertex), domeVerts, sizeof(SkyVertex));
}
public:
LifeMath::float3 SunDirection;
ITexture2D* mieTex;
ITexture2D* rayleighTex;
Sky()
:DayPhase(0), fExposure(-2.0f), updateTimeElapsed(0.0f), updatePeriod(2.0f), ShouldUpdateData(true)
{
waveLengths = LifeMath::float3(0.65f, 0.57f, 0.475f);
TimeStep = DayTime(0, 0, 1);
}
~Sky()
{
SAFE_DELETE(skyVb);
SAFE_DELETE(skyIb);
SAFE_DELETE(cbUpdate);
SAFE_DELETE(cbRender);
SAFE_DELETE(dsZDisable);
SAFE_DELETE(dsZEnable);
SAFE_DELETE(vertexLayout);
SAFE_DELETE(VS_Render);
// SAFE_DELETE(VS_Update);
SAFE_DELETE(PS_Render);
SAFE_DELETE(PS_Update);
SAFE_DELETE(mieTex);
SAFE_DELETE(rayleighTex);
SAFE_DELETE(skyDepth);
}
void Build()
{
cbUpdate = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(LifeMath::float4));
cbRender = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(cbRenderData));
dsZDisable = CG::me()->GetRenderer()->CreateDSState(false,false, COMPARISON_NEVER);
dsZEnable = CG::me()->GetRenderer()->CreateDSState(true,true, COMPARISON_LESS);
VS_Render = ResourceManager::me()->CompileUserShaderVS(String(_text("Sky.vsh")));
PS_Render = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_render.psh")));
PS_Update = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_update.psh")));
SunsetTime = DayTime(18, 2, 0);
SunrizeTime = DayTime(7, 10, 0);
Time = DayTime(12, 40, 0);
RecomputeData();
MrlTexSize = 512;
MrlTexSizeHalf = MrlTexSize / 2;
DomeN = 32;
GenerateDome();
mieTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT);
rayleighTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT);
skyDepth = CG::me()->GetRenderer()->CreateDepthTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_D16_UNORM);
//g_screenQuad = new Quad(0, 0, MrlTexSize, MrlTexSizeHalf, true);
}
void SetDayTime(const DayTime& time)
{
Time = time;
RecomputeData();
}
void Update(float dt)
{
updateTimeElapsed += dt;
if (updateTimeElapsed >= updatePeriod)
{
updateTimeElapsed = 0.0f;
ShouldUpdateData = true;
}
Time.Add((int)(dt * (float)TimeStep.ToSeconds()));
RecomputeData();
}
void Render(ITexture2D* sceneRt, ITexture2D* sceneDt, Camera* cam)
{
IRenderer* renderer = CG::me()->GetRenderer();
renderer->SetDepthStencilState(dsZDisable);
//Update mie and rayleigh textures
if (ShouldUpdateData)
{
ITexture2D* tex[] = {rayleighTex, mieTex};
renderer->SetTargets(tex, 2, skyDepth);
renderer->SetPixelShader(PS_Update);
cbUpdate->Update(&SunDirection, sizeof(SunDirection));
renderer->SetPSConstantBuffer(cbUpdate, 1);
renderer->SetViewport(LifeMath::Rect2i(0,0, MrlTexSize, MrlTexSizeHalf));
renderer->RenderToTextureNoPs();
renderer->UnbindRenderTargets();
ShouldUpdateData = false;
}
renderer->SetViewport(LifeMath::Rect2i(0,0, sceneRt->Width(), sceneRt->Height()));
renderer->SetVertexShader(VS_Render);
renderer->SetPixelShader(PS_Render);
float starIntensity = 0.7f;
float g = -0.990f;
float g2 = (-0.990f) * (-0.990f);
LifeMath::float4x4 sm;
Mat4x4LookAtLH(LifeMath::float3(0, 0, 0), cam->getDirection(), LifeMath::float3(0, 1, 0), sm);
cbRenderData data;
data.View = sm;
data.Proj = cam->getProj();
data.ViewProj = data.View * data.Proj;
data.SunDirection = SunDirection;
cbRender->Update(&data, sizeof(cbRenderData));
renderer->SetPSConstantBuffer(cbRender, 1);
renderer->SetVSConstantBuffer(cbRender, 1);
renderer->SetTargets(sceneRt, sceneDt);
////PS_Render.SetFloat("fExposure", fExposure);
////PS_Render.SetFloat("starIntensity", StarsIntensity);
////PS_Render.SetTexture("starSampler", starTex);
////PS_Render.SetTexture("mieSampler", mieTex);
////PS_Render.SetTexture("rayleighSampler", rayleighTex);
/*CG.Engine.Renderer.SetTextureFilterMin(TextureFilter.Point, 2);
CG.Engine.Renderer.SetTextureFilterMip(TextureFilter.Point, 2);
CG.Engine.Renderer.SetTextureFilterMag(TextureFilter.Point, 2);*/
////PS_Render.SetFloat3("v3SunDir", SunDirection);
renderer->SetPSTexture(rayleighTex,0);
renderer->SetPSTexture(mieTex,1);
////VS_Render.SetMatrix("matWorld", Matrix4x4.Identity);
////VS_Render.SetMatrix("matView", sm);
////VS_Render.SetMatrix("matProjection", renderer.MainCamera.ProjectionMatrix);
renderer->SetInputLayout(vertexLayout);
renderer->SetIndexBuffer(skyIb);
renderer->SetVertexBuffer(skyVb);
renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST);
renderer->DrawIndexed(0, DISize);
// renderer.DrawIndexedPrimitives(IPrimitiveTopology.TriangleList, 0, 0, SkyGeometry.NumberVertices, SkyGeometry.Subsets[0].Offset, SkyGeometry.Subsets[0].FaceCount);
renderer->SetDepthStencilState(dsZEnable);
}
};
}
#endif // Sky_h__
+924
View File
@@ -0,0 +1,924 @@
#ifndef Terrain_h__
#define Terrain_h__
#include "Globals.h"
#include "math/LifeMath.h"
#include "camera/Camera.h"
#include "ResourceManager.h"
#include <vector>
namespace LifeGraphics
{
enum TerrainDimention
{
TD_X128 = 128,
TD_X256 = 256,
TD_X512 = 512,
TD_X1024 = 1024,
TD_X2048 = 2048,
TD_X4096 = 4096,
TD_X8192 = 8192
};
struct TerraVertex
{
int index;
char nX;
char nZ;
USHORT height;
TerraVertex()
{
index = 0;
nX = nZ = 0;
height = 0;
}
TerraVertex(int _index, char _nx, char _nz, USHORT _height)
{
index = _index;
nX = _nx;
nZ = _nz;
height = _height;
}
};
struct TerraChunk
{
int LOD;
int Offset;
LifeCore::BoundingBox3D BoundingBox;
IIndexBuffer* IB;
int Column, Row;
bool Visible;
int NumVerts;
};
struct LOD
{
IIndexBuffer* Top;
IIndexBuffer* Bottom;
IIndexBuffer* Left;
IIndexBuffer* Right;
IIndexBuffer* TopLeft;
IIndexBuffer* TopRight;
IIndexBuffer* BottomLeft;
IIndexBuffer* BottomRight;
IIndexBuffer* full;
IIndexBuffer* allSides;
};
#define MAX_VISIBLE_DISTANCE 1025 //must be n ^ 2 + 1
struct TERRA_DATA
{
float size;
LifeMath::float3 sunDir;
};
class Terrain
{
public:
std::vector<LOD> lods;
IVertexBuffer* vb;
int vertexCount;
IInputLayout* layout;
TerraChunk* chunks;
IShader* terraVs;
IShader* terraPs;
IConstantBuffer* terraCb;
IShader* terraVs_g;
IShader* terraPs_g;
texture_ptr diffuse;
IRasterizerState* solidState;
IRasterizerState* wireState;
void* data;
IBitmapInfo* info;
USHORT* heightMap;
int TerrainWidth;
std::vector<TerraChunk*> visibleChunks;
static INLINE int fround(float val)
{
return static_cast<int>(floor(val + 0.5f));
}
static INLINE float clampFloat(float val, float min, float max)
{
if(val < min)return min;
if(val > max)return max;
return val;
}
static INLINE UINT blendrgb(UINT d, UINT s, UINT a)
{
const UINT dstrb = d & 0xFF00FF;
const UINT dstg = d & 0xFF00;
const UINT srcrb = s & 0xFF00FF;
const UINT srcg = s & 0xFF00;
UINT drb = srcrb - dstrb;
UINT dg = srcg - dstg;
drb *= a;
dg *= a;
drb >>= 8;
dg >>= 8;
UINT rb = (drb + dstrb) & 0xFF00FF;
UINT g = (dg + dstg) & 0xFF00;
return rb | g;
}
static INLINE UINT sampleTex(void* tex, IBitmapInfo* info, float tX, float tY)
{
tX = clampFloat(tX, 0.0f, 1.0f);
tY = clampFloat(tY, 0.0f, 1.0f);
float texelW = 1.0f / (float)(info->Width);
float texelH = 1.0f / (float)(info->Height);
// tX *= (1.0f - texelW * 2.0f);
// tY *= (1.0f - texelH * 2.0f);
int x = fround((tX * (float)(info->Width)));
int y = fround((tY * (float)(info->Height)));
UCHAR* ptr = reinterpret_cast<UCHAR*>(tex);
float pX = tX * info->Width;
float pY = tY * info->Height;
UINT frX = static_cast<UINT>((pX - floorf(pX))* 255.0f);
UINT frY = static_cast<UINT>((pY - floorf(pY))* 255.0f);
UINT* ptr2 = reinterpret_cast<UINT*>(tex);
UINT color;
if(info->Bpp < 4)
{
UINT tl = 0xff000000;
UINT tr = 0xff000000;
UINT rl = 0xff000000;
UINT rr = 0xff000000;
memcpy(&tl, ptr+ (y*info->Width + x)* info->Bpp, 3);
memcpy(&tr, ptr+ (y*info->Width + x + 1)* info->Bpp, 3);
memcpy(&rl, ptr+ ((y + 1)*info->Width + x)* info->Bpp, 3);
memcpy(&rr, ptr+ ((y + 1)*info->Width + x + 1)* info->Bpp, 3);
color = blendrgb ( blendrgb ( tl, tr, frX), blendrgb ( rl, rr, frX), frY);
}
return color;
}
#define MAX_HEIGHT 128
#define AS_FLOAT(ololo) ololo##.0f
Terrain(TerrainDimention dim, int chunkSize = 64, int maxVisibleRange = 100)
{
terraCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(TERRA_DATA));
diffuse = ResourceManager::me()->GetTexture(String(_text("root/Data/Textures/Terrain/shortGrass.png")));
ResourceManager::me()->ReadBitmap(String(_text("root/Data/Textures/hm.bmp")), &data, &info);
terraVs = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain.vsh")));
terraPs = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain.psh")));
terraVs_g = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain_g.vsh")));
terraPs_g = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain_g.psh")));
visibleCunkOffset = maxVisibleRange / chunkSize;
TerrainWidth = (int)dim;
ChunkWidth = chunkSize;
//Generate LOD IndexBuffers
//------------------------------------LOD_1-------------------
LOD1Full = GenerateLOD(chunkSize, 1, false, false, false, false);
LOD1TrimAllSides = GenerateLOD(chunkSize, 1, true, true, true, true);
LOD1TrimNorthEast = GenerateLOD(chunkSize, 1, true, false, false, true);
LOD1TrimNorthWest = GenerateLOD(chunkSize, 1, true, false, true, false);
LOD1TrimSouthEast = GenerateLOD(chunkSize, 1, false, true, false, true);
LOD1TrimSouthWest = GenerateLOD(chunkSize, 1, false, true, true, false);
//------------------------------------LOD_2-------------------
LOD2Full = GenerateLOD(chunkSize, 2, false, false, false, false);
LOD2TrimAllSides = GenerateLOD(chunkSize, 2, true, true, true, true);
LOD2TrimNorth = GenerateLOD(chunkSize, 2, true, false, false, false);
LOD2TrimSouth = GenerateLOD(chunkSize, 2, false, true, false, false);
LOD2TrimWest = GenerateLOD(chunkSize, 2, false, false, true, false);
LOD2TrimEast = GenerateLOD(chunkSize, 2, false, false, false, true);
LOD2TrimNorthEast = GenerateLOD(chunkSize, 2, true, false, false, true);
LOD2TrimNorthWest = GenerateLOD(chunkSize, 2, true, false, true, false);
LOD2TrimSouthEast = GenerateLOD(chunkSize, 2, false, true, false, true);
LOD2TrimSouthWest = GenerateLOD(chunkSize, 2, false, true, true, false);
//------------------------------------LOD_3-------------------
LOD3Full = GenerateLOD(chunkSize, 3, false, false, false, false);
LOD3TrimAllSides = GenerateLOD(chunkSize, 3, true, true, true, true);
LOD3TrimNorth = GenerateLOD(chunkSize, 3, true, false, false, false);
LOD3TrimSouth = GenerateLOD(chunkSize, 3, false, true, false, false);
LOD3TrimWest = GenerateLOD(chunkSize, 3, false, false, true, false);
LOD3TrimEast = GenerateLOD(chunkSize, 3, false, false, false, true);
LOD3TrimNorthEast = GenerateLOD(chunkSize, 3, true, false, false, true);
LOD3TrimNorthWest = GenerateLOD(chunkSize, 3, true, false, true, false);
LOD3TrimSouthEast = GenerateLOD(chunkSize, 3, false, true, false, true);
LOD3TrimSouthWest = GenerateLOD(chunkSize, 3, false, true, true, false);
//------------------------------------LOD_4-------------------
LOD4Full = GenerateLOD(chunkSize, 4, false, false, false, false);
LOD lod1;
lod1.allSides = LOD1TrimAllSides;
LOD lod2;
lod2.Top = LOD2TrimNorth;
lod2.Bottom = LOD2TrimSouth;
lod2.Left = LOD2TrimWest;
lod2.Right = LOD2TrimEast;
lod2.TopLeft = LOD2TrimNorthWest;
lod2.TopRight = LOD2TrimNorthEast;
lod2.BottomLeft = LOD2TrimSouthWest;
lod2.BottomRight = LOD2TrimSouthEast;
lod2.full = LOD2Full;
lod2.allSides = LOD2TrimAllSides;
LOD lod3;
lod3.Top = LOD3TrimNorth;
lod3.Bottom = LOD3TrimSouth;
lod3.Left = LOD3TrimWest;
lod3.Right = LOD3TrimEast;
lod3.TopLeft = LOD3TrimNorthWest;
lod3.TopRight = LOD3TrimNorthEast;
lod3.BottomLeft = LOD3TrimSouthWest;
lod3.BottomRight = LOD3TrimSouthEast;
lod3.full = LOD3Full;
lod3.allSides = LOD3TrimAllSides;
LOD lod4;
lod4.full = LOD4Full;
lods.push_back(lod1);
lods.push_back(lod2);
lods.push_back(lod3);
lods.push_back(lod4);
solidState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID);
wireState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_WIREFRAME);
vertexCount = (TerrainWidth + 1) * (TerrainWidth + 1);
vb = CG::me()->GetRenderer()->CreateVertexBufferDynamic(vertexCount * sizeof(TerraVertex), sizeof(TerraVertex));
float multiplier = (float)(0xffff/MAX_HEIGHT);
heightMap = new USHORT[(TerrainWidth + 1) * (TerrainWidth + 1)];
//load height map
for(int y = 0; y <= TerrainWidth; y++)
{
for(int x = 0; x <= TerrainWidth; x++)
{
UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2)));
USHORT h = (USHORT)(col & 0xff) * (0xffff / 0xff);
int index = y * (TerrainWidth + 1) + x;
heightMap[index] = h;
}
}
//smooth terrain heights
int numSmoothSteps = 1;
for(int i = 0; i < numSmoothSteps; i++)
{
//smooth by X
for(int y = 0; y <= TerrainWidth; y++)
{
for(int x = 1; x < TerrainWidth; x++)
{
int idL = y * (TerrainWidth + 1) + (x - 1);
int idC = y * (TerrainWidth + 1) + (x);
int idR = y * (TerrainWidth + 1) + (x + 1);
float h1 = (float)heightMap[idL];
float h2 = (float)heightMap[idC];
float h3 = (float)heightMap[idR];
USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f);
heightMap[idL] = avg;
heightMap[idC] = avg;
heightMap[idR] = avg;
}
}
//smooth by Y
for(int y = 1; y < TerrainWidth; y++)
{
for(int x = 0; x <= TerrainWidth; x++)
{
int idT = (y - 1) * (TerrainWidth + 1) + x;
int idC = y * (TerrainWidth + 1) + x;
int idB = (y + 1) * (TerrainWidth + 1) + x;
float h1 = (float)heightMap[idT];
float h2 = (float)heightMap[idC];
float h3 = (float)heightMap[idB];
USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f);
heightMap[idT] = avg;
heightMap[idC] = avg;
heightMap[idB] = avg;
}
}
}
//build terrain geometry
TerraVertex* vertexData = new TerraVertex[vertexCount];
for(int y = 0; y <= TerrainWidth; y++)
{
for(int x = 0; x <= TerrainWidth; x++)
{
int index = y * (TerrainWidth + 1) + x;
vertexData[index] = TerraVertex(index, 0,0, heightMap[index]);
}
}
delete info;
delete[] data;
//compute normals
LifeMath::float3 p1, p2, p3, d1, d2, n;
TerraVertex v1, v2, v3;
for(int y = 0; y < TerrainWidth; y++)
{
for(int x = 0; x < TerrainWidth; x++)
{
//first triangle
int i1 = y * (TerrainWidth + 1) + x;
int i2 = y * (TerrainWidth + 1) + x + 1;
int i3 = (y + 1) * (TerrainWidth + 1) + x;
v1 = vertexData[i1];
v2 = vertexData[i2];
v3 = vertexData[i3];
p1 = LifeMath::float3((float)(x), (float)v1.height / multiplier,-(float)(y));
p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y));
p3 = LifeMath::float3((float)(x), (float)v3.height / multiplier, -(float)(y + 1));
d1 = p2 - p1;
d2 = p3 - p1;
n = LifeMath::Vec3Cross(d1,d2);
LifeMath::Vec3Normalize(&n);
printf("ACHTUNG! Maybe wrong value computed for normal! What about NEAGTIVE numbers?\n");
char nnx = (char)(n.X * 127.0f);
char nnz = (char)(n.Z * 127.0f);
vertexData[i1].nX = nnx;
vertexData[i1].nZ = nnz;
vertexData[i2].nX = nnx;
vertexData[i2].nZ = nnz;
vertexData[i3].nX = nnx;
vertexData[i3].nZ = nnz;
//second triangle
i1 = (y + 1) * (TerrainWidth + 1) + x;
i2 = y * (TerrainWidth + 1) + x + 1;
i3 = (y + 1) * (TerrainWidth + 1) + x + 1;
v1 = vertexData[i1];
v2 = vertexData[i2];
v3 = vertexData[i3];
p1 = LifeMath::float3((float)(x), v1.height / multiplier, -(float)(y + 1));
p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y));
p3 = LifeMath::float3((float)(x + 1), v3.height / multiplier, -(float)(y + 1));
d1 = p2 - p1;
d2 = p3 - p1;
n = LifeMath::Vec3Cross(d1,d2);
LifeMath::Vec3Normalize(&n);
nnx = (char)(n.X * 127.0f);
nnz = (char)(n.Z * 127.0f);
vertexData[i1].nX = nnx;
vertexData[i1].nZ = nnz;
vertexData[i2].nX = nnx;
vertexData[i2].nZ = nnz;
vertexData[i3].nX = nnx;
vertexData[i3].nZ = nnz;
}
}
LifeCore::IDataStream* stm = vb->Map(0,LF_Discard);
stm->Write(vertexData, vertexCount * sizeof(TerraVertex));
vb->Unmap();
int chunkStride = (TerrainWidth / chunkSize);
//create and process chunk info
chunks = new TerraChunk[chunkStride * chunkStride];
for(int x = 0; x < chunkStride; x++)
{
for(int y = 0; y < chunkStride; y++)
{
int index = y * chunkStride + x;
chunks[index].Offset = y * (TerrainWidth + 1) * chunkSize + x * chunkSize;
chunks[index].Column = x;
chunks[index].Row = y;
chunks[index].LOD = 1;
chunks[index].IB = LOD1Full;
//now compute chunk bounding box
int minX = x * ChunkWidth;
int maxX = minX + ChunkWidth;
int minY = y * ChunkWidth;
int maxY = minY + ChunkWidth;
UINT minH;
UINT maxH;
minH = maxH = vertexData[minY * (TerrainWidth + 1) + minX].height;
for (int i = minX; i<=maxX; i++)
{
for (int j = minY; j<=maxY; j++)
{
UINT h = vertexData[j * (TerrainWidth + 1) + i].height;
if(minH > h)
minH = h;
if(maxH < h)
maxH = h;
}
}
chunks[index].BoundingBox.resize(LifeMath::float3((float)(x * ChunkWidth), (float)minH / multiplier, -(float)(maxY)),
LifeMath::float3((float)(maxX), (float)maxH / multiplier, -(float)(minY)));
/*printf("Chunk= X:%i Y:%i\nMin= X:%f Z:%f\nMax= X:%f Z:%f\n\n", x,y,chunks[index].BoundingBox.minimum().X,
chunks[index].BoundingBox.minimum().Z, chunks[index].BoundingBox.maximum().X,
chunks[index].BoundingBox.maximum().Z );*/
}
}
delete[] vertexData;
IInputElement elements[] =
{
IInputElement("POSITION", 0, 0, FORMAT_R32_UINT, 0, 0, 0),
IInputElement("TEXCOORD", 0, 4, FORMAT_R8G8_SINT, 0, 0, 0),
IInputElement("TEXCOORD", 1, 6, FORMAT_R16_UINT, 0, 0, 0),
};
layout = CG::me()->GetRenderer()->CreateInputLayout(elements, 3, terraVs);
}
~Terrain()
{
delete[] chunks;
SAFE_DELETE(vb);
SAFE_DELETE(layout);
SAFE_DELETE(terraVs);
SAFE_DELETE(terraPs_g);
diffuse->Release();
SAFE_DELETE(solidState);
SAFE_DELETE(wireState);
SAFE_DELETE_ARRAY(heightMap);
SAFE_DELETE(LOD1Full);
SAFE_DELETE(LOD1TrimAllSides);
SAFE_DELETE(LOD1TrimNorthEast);
SAFE_DELETE(LOD1TrimNorthWest);
SAFE_DELETE(LOD1TrimSouthEast);
SAFE_DELETE(LOD1TrimSouthWest);
SAFE_DELETE(LOD2Full);
SAFE_DELETE(LOD2TrimAllSides);
SAFE_DELETE(LOD2TrimNorth);
SAFE_DELETE(LOD2TrimSouth);
SAFE_DELETE(LOD2TrimEast);
SAFE_DELETE(LOD2TrimWest);
SAFE_DELETE(LOD2TrimNorthEast);
SAFE_DELETE(LOD2TrimNorthWest);
SAFE_DELETE(LOD2TrimSouthEast);
SAFE_DELETE(LOD2TrimSouthWest);
SAFE_DELETE(LOD3Full);
SAFE_DELETE(LOD3TrimAllSides);
SAFE_DELETE(LOD3TrimNorth);
SAFE_DELETE(LOD3TrimSouth);
SAFE_DELETE(LOD3TrimEast);
SAFE_DELETE(LOD3TrimWest);
SAFE_DELETE(LOD3TrimNorthEast);
SAFE_DELETE(LOD3TrimNorthWest);
SAFE_DELETE(LOD3TrimSouthEast);
SAFE_DELETE(LOD3TrimSouthWest);
SAFE_DELETE(LOD4Full);
}
void Update(Camera* cam, const LifeMath::float3& sunDir)
{
TERRA_DATA newData;
newData.size = (float)TerrainWidth;
newData.sunDir = sunDir;
terraCb->Update(&newData, sizeof(TERRA_DATA));
visibleChunks.clear();
LifeMath::float3 pos = cam->getPosition();
int pX = static_cast<int>(floorf(pos.X));
int pZ = static_cast<int>(floorf(pos.Z));
int col = pX / ChunkWidth;
int row = -pZ / ChunkWidth;
//int vis = 0;
//update all terrain chunks to minimal LOD (FIX IT: should not update ALL terrain)
int chunkStride = TerrainWidth / ChunkWidth;
for(int x = 0; x < chunkStride; x++)
{
for(int y = 0; y < chunkStride; y++)
{
if(cam->getFrustum()->BoxInFrustum(chunks[y * chunkStride + x].BoundingBox))
{
visibleChunks.push_back(&chunks[y * chunkStride + x]);
}
}
}
//check if cam is in terrain area
if(col >= 0 && row >= 0 && col < (TerrainWidth / ChunkWidth) && row < (TerrainWidth / ChunkWidth))
{
int numChunks = visibleChunks.size();
for(int i = 0; i < numChunks; i++)
{
TerraChunk* c = visibleChunks[i];
int diffCol = col - c->Column;
int diffRow = row - c->Row;
int lodNum = abs(diffCol) > abs(diffRow) ? abs(diffCol) : abs(diffRow);
if(lodNum < 3)
{
switch(lodNum)
{
case 0:
c->LOD = 1;
c->IB = LOD1TrimAllSides;
break;
default:
LOD* curLod = &lods[lodNum];
c->LOD = lodNum + 1;
if(abs(diffRow) > abs(diffCol))
{
if(diffRow > 0)
c->IB = curLod->Left;
else
c->IB = curLod->Right;
}
else if(abs(diffRow) < abs(diffCol))
{
if(diffCol > 0)
c->IB = curLod->Top;
else
c->IB = curLod->Bottom;
}
else
{
if(diffCol < 0 && diffRow < 0)
c->IB = curLod->BottomRight;
else if(diffCol > 0 && diffRow < 0)
c->IB = curLod->TopRight;
else if(diffCol < 0 && diffRow > 0)
c->IB = curLod->BottomLeft;
else
c->IB = curLod->TopLeft;
}
break;
}
}
else
{
c->LOD = 4;
c->IB = LOD4Full;
}
}
}
// printf("Visible chunks: %i\n", visibleChunks.size());
}
void Render(PassType pass)
{
IRenderer* renderer = CG::me()->GetRenderer();
renderer->SetPSConstantBuffer(terraCb, 2);
//renderer->SetRasterizerState(wireState);
renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST);
renderer->SetVertexBuffer(vb);
if(pass == PT_COMPOSE_G_BUF)
{
renderer->SetPixelShader(terraPs_g);
renderer->SetVertexShader(terraVs_g);
}
else if(pass == PT_RENDER_SHADOW_MAP)
{
renderer->SetVertexShader(terraVs);
}
else
{
renderer->SetPixelShader(terraPs);
renderer->SetVertexShader(terraVs);
}
renderer->SetInputLayout(layout);
renderer->SetPSTexture(diffuse.ptr(), 0);
int chunkStride = TerrainWidth / ChunkWidth;
int renderCount = visibleChunks.size();
for (int j = 0; j < renderCount; j++)
{
TerraChunk* c = visibleChunks[j];
//CG.GraphicsDevice.VertexFormat = g_terra.TerrainGeometryBuffer.Description.FVF;
//if (c->Visible)
//{
switch (c->LOD)
{
case 1:
renderer->SetIndexBuffer(c->IB);
//renderer->DrawIndexed(chunks[index].Offset, (ChunkWidth / 1) * (ChunkWidth / 1) * 2);
renderer->DrawIndexed(0, (ChunkWidth / 1) * (ChunkWidth / 1) * 2, c->Offset);
break;
case 2:
renderer->SetIndexBuffer(c->IB);
renderer->DrawIndexed(0, (ChunkWidth / 2) * (ChunkWidth / 2) * 2, c->Offset);
break;
case 3:
renderer->SetIndexBuffer(c->IB);
renderer->DrawIndexed(0, (ChunkWidth / 4) * (ChunkWidth / 4) * 2, c->Offset);
break;
case 4:
renderer->SetIndexBuffer(c->IB);
renderer->DrawIndexed(0, (ChunkWidth / 8) * (ChunkWidth / 8) * 2, c->Offset);
break;
}
//}
}
//renderer->SetRasterizerState(solidState);
}
float GetHeight(float x, float z) const
{
//return 0.0f;
/*
UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2)));
float r = (float)(col & 0xff) / 255.0f * AS_FLOAT(MAX_HEIGHT);
float g = (float)((col & 0xff00) >> 8) / 255.0f * AS_FLOAT(MAX_HEIGHT);
float b = (float)((col & 0xff0000) >> 16) / 255.0f * AS_FLOAT(MAX_HEIGHT);
float h = (r + g + b) / 3.0f * multiplier;*/
float multiplier = (float)(0xffff/MAX_HEIGHT);
z = -z;
if(x < 0 || x > TerrainWidth || z < 0 || z > TerrainWidth) return 0;
int iX = (int)x;
int iZ = (int)z;
float fX = x - (float)iX;
float fZ = z - (float)iZ;
float y1 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 0)]) / multiplier;
float y2 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 1)]) / multiplier;
float y3 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 1)]) / multiplier;
float y4 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 0)]) / multiplier;
if((1.0f - fZ) >= (fX))
return y1 + (y2 - y1) * fX + (y4 - y1) * fZ; //top triangle
else
return y3 + (y4 - y3) * (1.0f - fX) + (y2 - y3) * (1.0f - fZ); //bottom triangle
}
private:
IIndexBuffer* LOD1Full;
IIndexBuffer* LOD1TrimAllSides;
IIndexBuffer* LOD1TrimNorthEast;
IIndexBuffer* LOD1TrimNorthWest;
IIndexBuffer* LOD1TrimSouthEast;
IIndexBuffer* LOD1TrimSouthWest;
IIndexBuffer* LOD2Full;
IIndexBuffer* LOD2TrimAllSides;
IIndexBuffer* LOD2TrimNorth;
IIndexBuffer* LOD2TrimSouth;
IIndexBuffer* LOD2TrimEast;
IIndexBuffer* LOD2TrimWest;
IIndexBuffer* LOD2TrimNorthEast;
IIndexBuffer* LOD2TrimNorthWest;
IIndexBuffer* LOD2TrimSouthEast;
IIndexBuffer* LOD2TrimSouthWest;
IIndexBuffer* LOD3Full;
IIndexBuffer* LOD3TrimAllSides;
IIndexBuffer* LOD3TrimNorth;
IIndexBuffer* LOD3TrimSouth;
IIndexBuffer* LOD3TrimEast;
IIndexBuffer* LOD3TrimWest;
IIndexBuffer* LOD3TrimNorthEast;
IIndexBuffer* LOD3TrimNorthWest;
IIndexBuffer* LOD3TrimSouthEast;
IIndexBuffer* LOD3TrimSouthWest;
IIndexBuffer* LOD4Full;
int ChunkWidth;
int visibleCunkOffset;
IIndexBuffer* GenerateLOD(uint32 chunkLength, uint32 lodNumber, bool trimTop, bool trimBottom, bool trimLeft, bool trimRight)
{
uint32 mNum = 1, Counter = 0;
switch (lodNumber)
{
case 1:
mNum = 1;
break;
case 2:
mNum = 2;
break;
case 3:
mNum = 4;
break;
case 4:
mNum = 8;
break;
}
unsigned int* Indices = new unsigned int[(chunkLength / mNum) * (chunkLength / mNum) * 6];
for (uint32 i = 0; i < chunkLength / mNum; i++)
{
for (uint32 j = 0; j < chunkLength / mNum; j++)
{
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum;
Counter += 1;
Indices[Counter] = i * (TerrainWidth + 1) * mNum + j * mNum;
Counter += 1;
Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
Counter += 1;
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum;
Counter += 1;
Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
Counter += 1;
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
Counter += 1;
}
}
//-----------------LOD trimmers----------------------------
//trim top corner
if (trimTop)
{
for (unsigned int i = 0; i < (chunkLength / mNum); i++)
{
if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f))
{
//÷¸òíàÿ
Indices[i * chunkLength / mNum * 6 + 0] = 0;
Indices[i * chunkLength / mNum * 6 + 1] = 0;
Indices[i * chunkLength / mNum * 6 + 2] = 0;
}
else
{
Indices[i * chunkLength / mNum * 6 + 3] = Indices[(i + 1) * chunkLength / mNum * 6 + 3];
if (trimLeft == true)
{
if (i != 0)
Indices[i * chunkLength / mNum * 6 + 4] -= (mNum);
else
Indices[i * chunkLength / mNum * 6 + 0] -= (mNum);
}
else
{
Indices[i * chunkLength / mNum * 6 + 4] -= (mNum);
}
Indices[i * chunkLength / mNum * 6 + 0] += (mNum);
}
}
}
//trim bottom corner
if (trimBottom)
{
for (unsigned int i = 0; i < (chunkLength / mNum); i++)
{
if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f))
{
//÷¸òíàÿ
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 0] = 0;
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 1] = 0;
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 2] = 0;
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 4] -= mNum;
}
else
{
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 5] = Indices[(i + 2) * (chunkLength / mNum) * 6 - 6 + 5];
}
}
}
int offset = (chunkLength / mNum) * ((chunkLength / mNum) - 1) * 6;
if (trimRight)
{
//Trim right corner
for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++)
{
if ((int)((float)i / 2.0f) == (float)i / 2.0f)
{
//÷¸òíàÿ
Indices[offset + (i - 1) * 6 + 0] += (mNum);
Indices[offset + (i - 1) * 6 + 3] = 0;
Indices[offset + (i - 1) * 6 + 4] = 0;
Indices[offset + (i - 1) * 6 + 5] = 0;
}
else
{
Indices[offset + (i - 1) * 6 + 5] += (mNum);
}
}
}
if (trimLeft)
{
//Trim left corner
offset = (chunkLength / mNum) * 6;
for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++)
{
if ((int)((float)i / 2.0f) == (float)i / 2.0f)
{
Indices[(i - 1) * 6 + 0] = 0;
Indices[(i - 1) * 6 + 1] = 0;
Indices[(i - 1) * 6 + 2] = 0;
}
else
{
Indices[(i - 1) * 6 + 0] += (mNum);
Indices[(i - 1) * 6 + 2] += (mNum);
Indices[(i - 1) * 6 + 4] -= (mNum);
}
}
}
IIndexBuffer* _ib = CG::me()->GetRenderer()->CreateIndexBuffer((chunkLength / mNum) * (chunkLength / mNum) * 6 * sizeof(unsigned int),Indices, FALSE);
return _ib;
}
static void GenerateMaxLOD(int chunkLength, int* indices)
{
// int[] indices = new int[chunkLength * chunkLength * 6];
int counter = 0;
for (int i = 0; i < chunkLength; i++)
{
for (int j = 0; j < chunkLength; j++)
{
//First cell's triangle
indices[counter] = i * (chunkLength + 1) + (j + 1);
counter += 1;
indices[counter] = (i + 1) * (chunkLength + 1) + j;
counter += 1;
indices[counter] = i * (chunkLength + 1) + j;
counter += 1;
//Second cell's triangle
indices[counter] = (i + 1) * (chunkLength + 1) + (j + 1);
counter += 1;
indices[counter] = (i + 1) * (chunkLength + 1) + j;
counter += 1;
indices[counter] = i * (chunkLength + 1) + (j + 1);
counter += 1;
}
}
}
};
}
#endif // Terrain_h__
+12
View File
@@ -0,0 +1,12 @@
#ifndef TypesVideo_h__
#define TypesVideo_h__
#include "resource_ptr.h"
#include "render/ITexture2D.h"
#include "render/ITextureCube.h"
namespace LifeGraphics
{
typedef resource_ptr<ITexture2D> texture_ptr;
}
#endif // TypesVideo_h__
+64
View File
@@ -0,0 +1,64 @@
#include "math/LifeMath.h"
namespace LifeGraphics
{
enum VERTEX_FORMAT
{
VF_POSITION = 0,
VF_TEXCOORD = 1 << 0
};
namespace Vertex
{
struct SVertex
{
LifeMath::float3 Position;
LifeMath::float2 Texcoord;
LifeMath::float3 Normal;
static int Stride(){ return sizeof(LifeMath::float3) * 2 + sizeof(LifeMath::float2); }
};
struct SVertexTbn
{
LifeMath::float3 Position;
LifeMath::float2 Texcoord;
LifeMath::float3 Normal;
LifeMath::float3 Tangent;
LifeMath::float3 Binormal;
static int Stride(){ return sizeof(LifeMath::float3) * 4 + sizeof(LifeMath::float2); }
};
struct SVertexTbnSkin
{
LifeMath::float3 Position;
LifeMath::float2 Texcoord;
LifeMath::float3 Normal;
LifeMath::float3 Tangent;
LifeMath::float3 Binormal;
LifeMath::float4 BlendIndices;
LifeMath::float4 BlendWeights;
static int Stride(){ return sizeof(LifeMath::float3) * 4 + sizeof(LifeMath::float2) + sizeof(LifeMath::float4) * 2; }
};
/*if(header.expSkin)
{
numElements = 7;
elements = new IInputElement[numElements];
elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0);
elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[5] = IInputElement("BLENDINDICES", 0, 56, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0);
elements[6] = IInputElement("BLENDWEIGHT", 0, 72, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0);
}
else
{
elements = new IInputElement[numElements];
elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0);
elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
}*/
}
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef XML_h__
#define XML_h__
#include "pugixml.hpp"
class LifeXMLWriter : public pugi::xml_writer
{
public:
std::string result;
int length;
LifeXMLWriter()
:length(0)
{
}
virtual void write(const void* data, size_t size)
{
result += std::string(static_cast<const char*>(data), size);
length += size;
}
};
#endif // XML_h__
+329
View File
@@ -0,0 +1,329 @@
#ifndef Camera_h__
#define Camera_h__
#include "IGraphicsNode.h"
#include "math/LifeMath.h"
#include "camera/Frustum.h"
namespace LifeGraphics
{
class Camera : public IGraphicsNode
{
private:
bool isViewValid;
bool isProjValid;
float fov;
float nearPlane;
float farPlane;
float viewAspect;
LifeMath::float3 right;
LifeMath::float3 eye;
LifeMath::float3 at;
LifeMath::float3 up;
float yaw, pitch, roll;
Frustum frustum;
LifeMath::float3 ViewDirection;
LifeMath::float4x4 viewMatrix;
LifeMath::float4x4 projectionMatrix;
bool freeCam;
LifeMath::float3 fDir;
NodeType getType()
{
return NT_CAMERA;
}
void UpdatePerspectiveMatrix()
{
Mat4x4PerspectiveFOV(fov, viewAspect, nearPlane, farPlane, projectionMatrix);
isProjValid = true;
frustum.UpdateFrustum(viewMatrix * projectionMatrix);
}
void ComputeView()
{
//g_viewMatrix = Matrix4x4.LookAtLH(g_eye, g_at, g_up);
ViewDirection = at - eye;
LifeMath::Vec3Normalize(&ViewDirection, &ViewDirection);
up = LifeMath::float3(0,1,0);
//fixup UP vector
if(LifeMath::Vec3Dot(&ViewDirection, &up) > 0.998f)
{
up = LifeMath::float3(0,0,-1);
}
else if(LifeMath::Vec3Dot(&ViewDirection, &up) < -0.998f)
{
up = LifeMath::float3(0,0,1);
}
//orthoganalize right vector
LifeMath::Vec3Cross(up, ViewDirection, right);
LifeMath::Vec3Normalize(&right);
//orthoganalize up vector
LifeMath::Vec3Cross(ViewDirection, right, up);
LifeMath::Vec3Normalize(&up);
//compute view matrix
float x = -LifeMath::Vec3Dot(&right, &eye);
float y = -LifeMath::Vec3Dot(&up, &eye);
float z = -LifeMath::Vec3Dot(&ViewDirection, &eye);
viewMatrix.M11 = right.X;
viewMatrix.M12 = up.X;
viewMatrix.M13 = ViewDirection.X;
viewMatrix.M14 = 0;
viewMatrix.M21 = right.Y;
viewMatrix.M22 = up.Y;
viewMatrix.M23 = ViewDirection.Y;
viewMatrix.M24 = 0;
viewMatrix.M31 = right.Z;
viewMatrix.M32 = up.Z;
viewMatrix.M33 = ViewDirection.Z;
viewMatrix.M34 = 0;
viewMatrix.M41 = x;
viewMatrix.M42 = y;
viewMatrix.M43 = z;
viewMatrix.M44 = 1.0f;
isViewValid = true;
frustum.UpdateFrustum(viewMatrix * projectionMatrix);
}
public:
Camera();
~Camera();
void update(float dt)
{
}
void setAspect(float aspect)
{
viewAspect = aspect;
isProjValid = false;
}
void setFov(float _fov)
{
fov = _fov;
isProjValid = false;
}
void setNear(float val)
{
nearPlane = val;
isProjValid = false;
}
void setFar(float val)
{
farPlane = val;
isProjValid = false;
}
float getNear() const
{
return nearPlane;
}
float getFar() const
{
return farPlane;
}
LifeMath::float4x4 getView()
{
if(isViewValid)
{
return viewMatrix;
}
else
{
ComputeView();
isViewValid = true;
return viewMatrix;
}
}
LifeMath::float4x4 getProj()
{
if(isProjValid)
{
return projectionMatrix;
}
else
{
UpdatePerspectiveMatrix();
isProjValid = true;
return projectionMatrix;
}
}
LifeMath::float3 getDirection()
{
return ViewDirection;
}
LifeMath::float3 getRight()
{
return right;
}
void setPosition(float x, float y, float z)
{
eye = LifeMath::float3(x, y, z);
isViewValid = false;
}
void setPosition(const LifeMath::float3& position)
{
eye = position;
isViewValid = false;
//ComputeView();
/*isViewValid = false;*/
}
void setDirection(LifeMath::float3& direction)
{
at = direction;
//at = direction - eye;
//LifeMath::Vec3Normalize(&at);
up.X = 0.0f;
up.Y = 1.0f;
up.Z = 0.0f;
isViewValid = false;
//LifeMath::Vec3Cross(up, at, right);
//ComputeView();
}
Frustum* getFrustum()
{
bool updateFrustum = false;
if(!isViewValid)
{
ComputeView();
updateFrustum = true;
}
if(!isProjValid)
{
UpdatePerspectiveMatrix();
updateFrustum = true;
}
return &frustum;
}
const LifeMath::float3& getPosition() const
{
return eye;
}
float getFov() const
{
return fov;
}
float getAspect() const
{
return viewAspect;
}
const LifeMath::float3& getUp() const
{
return up;
}
void Yaw(float angle)
{
yaw += angle;
LifeMath::float3 axis = LifeMath::float3(0.0f, 1.0f, 0.0f);
LifeMath::float4x4 r;
Mat4x4RotationAxis(&axis, angle, &r);
if (freeCam)
{
Vec3TransformCoordinate(right, r, right);
Vec3TransformCoordinate(at, r, at);
}
else
{
Vec3TransformCoordinate(fDir, r, fDir);
Vec3TransformCoordinate(right, r, right);
}
isViewValid = false;
}
void Pitch(float angle)
{
pitch += angle;
LifeMath::float4x4 r;
Mat4x4RotationAxis(&right, angle, &r);
if (freeCam)
{
Vec3TransformCoordinate(up, r, up);
Vec3TransformCoordinate(at, r, at);
}
else
{
Vec3TransformCoordinate(up, r, up);
Vec3TransformCoordinate(fDir, r, fDir);
}
isViewValid = false;
}
void Roll(float angle)
{
roll += angle;
LifeMath::float4x4 r;
Mat4x4RotationAxis(&at, angle, &r);
Vec3TransformCoordinate(up, r, up);
Vec3TransformCoordinate(right, r, at);
isViewValid = false;
}
void GetCorners(LifeMath::float3* corners)
{
if(!isViewValid)
ComputeView();
if(!isProjValid)
UpdatePerspectiveMatrix();
LifeMath::float4x4 vp = viewMatrix * projectionMatrix;
Mat4x4Invert(&vp);
for (int i = 0; i < 8; i++)
{
corners[i] = Vec3TransformCoordinate(vp, baseCorners[i]);
}
}
void SetupBasis(const LifeMath::float3& _pos, const LifeMath::float3& _front, const LifeMath::float3& _top, const LifeMath::float3& _right)
{
eye = _pos;
right = _right;
up = _top;
at = _front;
ViewDirection = at;
LifeMath::Vec3Normalize(&right);
LifeMath::Vec3Normalize(&at);
LifeMath::Vec3Normalize(&up);
//compute view matrix
float x = -LifeMath::Vec3Dot(&right, &eye);
float y = -LifeMath::Vec3Dot(&up, &eye);
float z = -LifeMath::Vec3Dot(&at, &eye);
viewMatrix.M11 = right.X;
viewMatrix.M12 = up.X;
viewMatrix.M13 = at.X;
viewMatrix.M14 = 0.0f;
viewMatrix.M21 = right.Y;
viewMatrix.M22 = up.Y;
viewMatrix.M23 = at.Y;
viewMatrix.M24 = 0.0f;
viewMatrix.M31 = right.Z;
viewMatrix.M32 = up.Z;
viewMatrix.M33 = at.Z;
viewMatrix.M34 = 0.0f;
viewMatrix.M41 = x;
viewMatrix.M42 = y;
viewMatrix.M43 = z;
viewMatrix.M44 = 1.0f;
isViewValid = true;
}
};
}
#endif // Camera_h__
+186
View File
@@ -0,0 +1,186 @@
#ifndef Frustum_h__
#define Frustum_h__
#include "math/LifeMath.h"
#include <BoundingBox3D.h>
#include "BoundingSphere.h"
namespace LifeGraphics
{
enum BoxIntersectionResult
{
Inside = 0, Outside = 1, Intersection = 2
};
enum FrustumPlane
{
Top = 0, Bottom = 0, Left = 0, Right = 0, Near = 0, Far = 0
};
static const LifeMath::float3 baseCorners[] = {
//front plane
LifeMath::float3(-1.0f, 1.0f, 1.0f),
LifeMath::float3(1.0f, 1.0f, 1.0f),
LifeMath::float3(1.0f, -1.0f, 1.0f),
LifeMath::float3(-1.0f, -1.0f, 1.0f),
//rear plane
LifeMath::float3(-1.0f, 1.0f, -1.0f),
LifeMath::float3(1.0f, 1.0f, -1.0f),
LifeMath::float3(1.0f, -1.0f, -1.0f),
LifeMath::float3(-1.0f, -1.0f, -1.0f)
};
class Frustum
{
private:
LifeMath::Plane frustrumPlanes[6];
LifeMath::float3 corners[8];
LifeMath::float4x4 vp;
public:
Frustum()
{
for (int i = 0; i < 6; i++)
frustrumPlanes[i] = LifeMath::Plane(LifeMath::float3(0.0f, 0.0f, 0.0f), LifeMath::float3(0.0f, 1.0f, 0.0f));
}
Frustum(LifeMath::Plane& _near, LifeMath::Plane& _far, LifeMath::Plane& _top, LifeMath::Plane& _bottom,
LifeMath::Plane& _left, LifeMath::Plane& _right)
{
frustrumPlanes[0] = _top;
frustrumPlanes[1] = _bottom;
frustrumPlanes[2] = _left;
frustrumPlanes[3] = _right;
frustrumPlanes[4] = _near;
frustrumPlanes[5] = _far;
}
Frustum(const LifeMath::float4x4& viewProjection)
{
UpdateFrustum(viewProjection);
}
~Frustum(){}
void UpdateFrustum(const LifeMath::float4x4& viewProjection)
{
vp = viewProjection;
// Top plane
frustrumPlanes[0] = LifeMath::Plane(
viewProjection.M14 - viewProjection.M12,
viewProjection.M24 - viewProjection.M22,
viewProjection.M34 - viewProjection.M32,
viewProjection.M44 - viewProjection.M42);
// Bottom plane
frustrumPlanes[1] = LifeMath::Plane(
viewProjection.M14 + viewProjection.M12,
viewProjection.M24 + viewProjection.M22,
viewProjection.M34 + viewProjection.M32,
viewProjection.M44 + viewProjection.M42);
// Left plane
frustrumPlanes[2] = LifeMath::Plane(
viewProjection.M14 + viewProjection.M11,
viewProjection.M24 + viewProjection.M21,
viewProjection.M34 + viewProjection.M31,
viewProjection.M44 + viewProjection.M41);
// Right plane
frustrumPlanes[3] = LifeMath::Plane(
viewProjection.M14 - viewProjection.M11,
viewProjection.M24 - viewProjection.M21,
viewProjection.M34 - viewProjection.M31,
viewProjection.M44 - viewProjection.M41);
// Near plane
frustrumPlanes[4] = LifeMath::Plane(
viewProjection.M13,
viewProjection.M23,
viewProjection.M33,
viewProjection.M43);
// Far plane
frustrumPlanes[5] = LifeMath::Plane(
viewProjection.M14 - viewProjection.M13,
viewProjection.M24 - viewProjection.M23,
viewProjection.M34 - viewProjection.M33,
viewProjection.M44 - viewProjection.M43);
// Normalize planes
for (int i = 0; i < 6; i++)
{
LifeMath::PlaneNormalize(frustrumPlanes[i]);
}
}
bool SphereInFrustum(const LifeMath::float3& center, float radius) const
{
LifeMath::float4 position = LifeMath::float4(center.X, center.Y, center.Z, 1.0f);
for (int i = 0; i < 6; i++)
if(LifeMath::PlaneDot(frustrumPlanes[i], position) + radius < 0)
return false;
return true;
}
bool SphereInFrustum(const BoundingSphere* sphere) const
{
LifeMath::float4 position = LifeMath::float4(sphere->center.X, sphere->center.Y, sphere->center.Z, 1.0f);
for (int i = 0; i < 6; i++)
if(PlaneDot(frustrumPlanes[i], position) + sphere->radius < 0)
return false;
return true;
}
bool BoxInFrustum(const LifeCore::BoundingBox3D& box) const
{
LifeMath::float3 corners[8];
box.GetCorners(corners);
for (int i = 0; i < 6; i++)
{
if (PlaneDot(frustrumPlanes[i], corners[0]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[1]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[2]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[3]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[4]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[5]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[6]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[7]) < 0)
{
return false;
}
}
return true;
}
bool BoxInFrustum(const LifeMath::float3* corners) const
{
for (int i = 0; i < 6; i++)
{
if (PlaneDot(frustrumPlanes[i], corners[0]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[1]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[2]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[3]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[4]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[5]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[6]) < 0 &&
PlaneDot(frustrumPlanes[i], corners[7]) < 0)
{
return false;
}
}
return true;
}
const LifeMath::float3* GetCorners()
{
LifeMath::float4x4 ivp;
ivp = LifeMath::Mat4x4Invert(&vp);
for (int i = 0; i < 8; i++)
{
LifeMath::Vec3TransformCoordinate(baseCorners[i], ivp, corners[i]);
}
return corners;
}
};
}
#endif // Frustum_h__
+60
View File
@@ -0,0 +1,60 @@
#ifndef constants_h__
#define constants_h__
#include "math/LifeMath.h"
struct PER_CAMERA_CONSTANTS
{
LifeMath::float4x4 mView;
LifeMath::float4x4 mProj;
LifeMath::float4x4 mInvVP;
LifeMath::float3 camPos;
float d0;
LifeMath::float3 camDir;
float d1;
LifeMath::float4 camNearFar;
LifeMath::float3 corner3;
float corner3_dummy;
LifeMath::float3 corner2;
float corner2_dummy;
LifeMath::float3 corner1;
float corner1_dummy;
LifeMath::float3 corner0;
float corner0_dummy;
};
struct POINT_LIGHT_DATA
{
LifeMath::float3 Position;
float Intensity;
LifeMath::float3 Color;
float Range;
};
struct DIR_LIGHT_DATA
{
LifeMath::float3 Direction;
float Intensity;
LifeMath::float3 Color;
float SpecularPow;
};
struct SPOT_LIGHT_DATA
{
LifeMath::float3 Direction;
float InnerAngle;
LifeMath::float3 Position;
float Intensity;
LifeMath::float3 Color;
float Range;
float OuterAngle;
float ZNear;
float dummy2;
float dummy3;
LifeMath::float4x4 lightMatrix;
LifeMath::float4x4 lightView;
LifeMath::float4x4 meshMatrix;
};
#endif // constants_h__
+231
View File
@@ -0,0 +1,231 @@
#ifndef IDebugDrawer_h__
#define IDebugDrawer_h__
#include "render/IRenderer.h"
#include "math/LifeMath.h"
#include <math/Spline.h>
namespace LifeGraphics
{
#define MAX_VERTEX_COUNT 1024
struct DebugVertex
{
LifeMath::float3 position;
LifeMath::float3 color;
const DebugVertex operator *(float val) const
{
DebugVertex result;
result.color = this->color * val;
result.position = this->position * val;
return result;
}
const DebugVertex operator +(const DebugVertex& val) const
{
DebugVertex result;
result.color = this->color + val.color;
result.position = this->position + val.position;
return result;
}
const DebugVertex& operator *=(float val)
{
this->color *= val;
this->position *= val;
return *this;
}
};
struct CB_2D_DATA
{
LifeMath::float4 screen_size;
};
class IDebugDrawer
{
private:
IShader* debugVS;
IShader* debugPS;
IShader* debugVS_2d;
IShader* debugPS_2d;
IInputLayout* inputLayout;
IVertexBuffer* debugVB;
DebugVertex geom[MAX_VERTEX_COUNT];
int vertexCount;
IConstantBuffer* cb_2d;
DebugVertex* buf;
public:
IDebugDrawer(IRenderer* _renderer)
:vertexCount(0)
{
//Vertex shader
String vs(STR(
"struct VS_INPUT" \
"{" \
" float4 Position : POSITION;" \
" float3 Color : LineColor;" \
"}; " \
"struct VS_OUTPUT " \
"{" \
" float4 Position : SV_Position;" \
" float3 Color : TEXCOORD0;" \
"};" \
"cbuffer perCameraData : register(b1)" \
"{" \
" row_major matrix matView;" \
" row_major matrix matProjection;" \
" row_major matrix matInvVP;" \
" float4 camPos;" \
" float4 camDir;" \
" float4 camNearFar;" \
" float4 corners[4];" \
"};"\
"VS_OUTPUT main_VS( VS_INPUT Input )" \
"{"\
" VS_OUTPUT Output = (VS_OUTPUT)0;" \
" float4 pos = float4(Input.Position.xyz, 1.0f);" \
" Output.Color = Input.Color;" \
" Output.Position = mul(pos, matInvVP);" \
" return( Output );" \
"}"
));
//Pixel shader
String ps(STR(
"struct PS_INPUT " \
"{" \
" float4 Position : SV_Position;" \
" float3 Color : TEXCOORD0;" \
"};" \
"float4 main_PS( PS_INPUT Input ) : SV_Target" \
"{" \
" return float4(Input.Color, 1.0f);" \
"}"
));
String vs_line_2d(STR(
"cbuffer RT_Size: register(b1)" \
"{float bbWidth : packoffset(c0.x);float bbHeight : packoffset(c0.y);};" \
"struct VS_INPUT {float3 Position : POSITION0;float3 Color : LineColor0;};" \
"struct VS_OUTPUT {float4 Position : SV_Position;float4 Color :TEXCOORD0;};" \
"VS_OUTPUT main_VS( VS_INPUT Input ){" \
"VS_OUTPUT Output;Output.Position = float4(Input.Position.xy, 0.0f, 1.0f);" \
"Output.Position.xy = Output.Position.xy/float2(bbWidth, -bbHeight)*2.0f + float2(-1.0f,1.0f);" \
"Output.Color = float4(Input.Color.xyz, 1.0f); return( Output );}"
));
String ps_2d_line(STR(
"struct PS_INPUT {" \
"float4 Position : SV_Position;" \
"float4 Color : TEXCOORD0;};" \
"float4 main_PS( PS_INPUT Input ) : SV_Target" \
"{ return Input.Color;}"
));
buf = new DebugVertex[2*256];
debugVS = ResourceManager::me()->CompileUserShaderVS(vs.c_str(), vs.length());
debugPS = ResourceManager::me()->CompileUserShaderPS(ps.c_str(), ps.length());
debugVS_2d = ResourceManager::me()->CompileUserShaderVS(vs_line_2d.c_str(), vs_line_2d.length());
debugPS_2d = ResourceManager::me()->CompileUserShaderPS(ps_2d_line.c_str(), ps_2d_line.length());
IInputElement* elements = new IInputElement[2];
elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
elements[1] = IInputElement("LineColor", 0, 12, FORMAT_R32G32B32_FLOAT, 0, 0, 0);
inputLayout = CG::me()->GetRenderer()->CreateInputLayout(elements, 2, debugVS);
debugVB = CG::me()->GetRenderer()->CreateVertexBufferDynamic(sizeof(DebugVertex)* MAX_VERTEX_COUNT,sizeof(DebugVertex));
cb_2d = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(CB_2D_DATA));
}
void DrawSpline2D(DebugVertex* points, int discr_rate)
{
int offset = 0;
DebugVertex prev;
prev = points[0];
for(int i = 1; i <= discr_rate; i++)
{
//DebugVertex newP;
DebugVertex newP = LifeCore::CubicBezier<DebugVertex>((1.0f / (float)discr_rate) * (float)i, points[0], points[1], points[2], points[3]);
buf[offset++] = prev;
buf[offset++] = newP;
prev = newP;
}
DrawLines2D(buf, discr_rate);
}
void DrawLines2D(DebugVertex* data, int line_count)
{
LifeCore::IDataStream* stm = debugVB->Map(0, LF_Discard | LF_NoOverwrite);
stm->Write(data, line_count * 2 * sizeof(DebugVertex));
debugVB->Unmap();
CB_2D_DATA d;
d.screen_size = LifeMath::float4(640, 480,0,0);
cb_2d->Update(&d, sizeof(CB_2D_DATA));
IRenderer* r = CG::me()->GetRenderer();
r->SetVSConstantBuffer(cb_2d, 1);
r->SetVertexBuffer(debugVB);
r->SetInputLayout(inputLayout);
r->SetPrimitiveTopology(PT_LINE_LIST);
r->SetVertexShader(debugVS_2d);
r->SetPixelShader(debugPS_2d);
r->Draw(line_count * 2, 0);
}
void Render()
{
if(vertexCount > 1)
{
LifeCore::IDataStream* stm = debugVB->Map(0, LF_Discard);
stm->Write(&geom[0], vertexCount * sizeof(DebugVertex));
debugVB->Unmap();
IRenderer* r = CG::me()->GetRenderer();
r->SetVertexBuffer(debugVB);
r->SetInputLayout(inputLayout);
r->SetPrimitiveTopology(PT_LINE_LIST);
r->SetVertexShader(debugVS);
r->SetPixelShader(debugPS);
r->Draw(vertexCount, 0);
}
}
void Flush()
{
vertexCount = 0;
}
/*void PushLine(const LifeMath::float3& v1, const LifeMath::float3& v2)
{
if(vertexCount < MAX_VERTEX_COUNT)
{
geom[vertexCount] = v1;
vertexCount++;
}
if(vertexCount < MAX_VERTEX_COUNT)
{
geom[vertexCount] = v2;
vertexCount++;
}
}*/
void PushLine(const DebugVertex& v1, const DebugVertex& v2)
{
//if(vertexCount < MAX_VERTEX_COUNT)
//{
geom[vertexCount++] = v1;
//}
//if(vertexCount < MAX_VERTEX_COUNT)
//{
geom[vertexCount++] = v2;
//}
}
};
}
#endif // IDebugDrawer_h__
+455
View File
@@ -0,0 +1,455 @@
#ifndef passPSSM_h__
#define passPSSM_h__
#include "Globals.h"
#include "math/LifeMath.h"
#include "camera/Camera.h"
#include <vector>
namespace LifeGraphics
{
struct PSSM_CONST
{
LifeMath::float4x4 pssmMat[4];
LifeMath::float4 splitRegions[4];
float pssmSize;
LifeMath::float3 dummy_pssm;
};
class passPSSM
{
public:
IConstantBuffer* cbPssm;
IBlendState* shadowBlendState;
IBlendState* restoreBlendState;
LifeMath::float3 points[8];
int splitCount;
float fSplitDistances[4];
float fSplitSchemeLambda;
int depthSize;
LifeMath::float4x4 mLightView;
LifeMath::float4x4 mLightProj;
LifeMath::float3 vLightSource;
LifeMath::float3 vLightTarget;
float fLightNear;
float fLightFar; // dynamically adjusted
float fLightFarMax;
float fLightFOV;
LifeMath::float4x4 lViews[4];
LifeMath::float4x4 lProjs[4];
ITexture2D* depth;
IShader* rtdShader;
Camera* sceneCam;
Frustum f;
Light* light;
LifeMath::Rect2i viewRegions[4];
float fNear;
float fFar;
std::vector<LifeMath::float4> splitRegions;
float clampf(float val, float min, float max)
{
if(val < min) return min;
if(val > max) return max;
return val;
}
~passPSSM()
{
if(cbPssm)
delete cbPssm;
if(depth)
delete depth;
if(rtdShader)
delete rtdShader;
}
passPSSM()
{
cbPssm = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PSSM_CONST));
fLightNear = 0.1f;
fLightFar = 350.0f; // dynamically adjusted
fLightFarMax = 350.0f;
fLightFOV = 3.14159265358979f / 2.0f;
splitCount = 3;
fSplitSchemeLambda = 0.92f;
depthSize = 2048;
ComputeDepthRegionDistribution();
}
void ComputeDepthRegionDistribution()
{
splitRegions.clear();
LifeMath::float4 region0;
LifeMath::float4 region1;
LifeMath::float4 region2;
LifeMath::float4 region3;
printf("FIX RECTANGLE!!!!\n");
switch(splitCount)
{
case 1:
//----------|
//| |
//| 1 |
//| |
//| |
//----------|
region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 1.0f);
viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize);
splitRegions.push_back(region0);
break;
case 2:
//----------|
//| 1 |
//| |
//-----------
//| |
//| 2 |
//----------|
region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f);
viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize / 2);
region1 = LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f);
viewRegions[1] = LifeMath::Rect2i(0, depthSize / 2, depthSize, depthSize / 2);
splitRegions.push_back(region0);
splitRegions.push_back(region1);
break;
case 3:
region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f);
viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize / 2);
region1 = LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f);
viewRegions[1] = LifeMath::Rect2i(0, depthSize / 2, depthSize / 2, depthSize / 2);
region2 = LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f);
viewRegions[2] = LifeMath::Rect2i(depthSize / 2, depthSize / 2, depthSize / 2, depthSize / 2);
splitRegions.push_back(region0);
splitRegions.push_back(region1);
splitRegions.push_back(region2);
break;
case 4:
region0 = LifeMath::float4(0.0f, 0.0f, 0.5f, 0.5f);
viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize / 2, depthSize / 2);
region1 = LifeMath::float4(0.5f, 0.0f, 0.5f, 0.5f);
viewRegions[1] = LifeMath::Rect2i(depthSize / 2, 0, depthSize / 2, depthSize / 2);
region2 = LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f);
viewRegions[2] = LifeMath::Rect2i(0, depthSize / 2, depthSize / 2, depthSize / 2);
region3 = LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f);
viewRegions[3] = LifeMath::Rect2i(depthSize / 2, depthSize / 2, depthSize / 2, depthSize / 2);
splitRegions.push_back(region0);
splitRegions.push_back(region1);
splitRegions.push_back(region2);
splitRegions.push_back(region3);
break;
}
}
void Init()
{
//cam1 = new Camera(1, 1, "");
depth = CG::me()->GetRenderer()->CreateDepthTarget(depthSize, depthSize, FORMAT_R32_TYPELESS);
rtdShader = ResourceManager::me()->CompileUserShaderPS(AS_STRING("RTD_PCF.psh"));
shadowBlendState = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ZERO, BLEND_ONE, 0);
restoreBlendState = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ZERO, 1 | 2 | 4 | 8);
}
void Begin(Camera* _sceneCam, Light* _light)
{
light = _light;
sceneCam = _sceneCam;
IRenderer* renderer = CG::me()->GetRenderer();
CalculateSplitPlanes(sceneCam);
renderer->SetPixelShader(rtdShader);
//renderer.SetRenderState(IRenderState.AlphaBlendEnable, false);
//renderer.SetRenderState(IRenderState.AlphaTestEnable, false);
renderer->SetTargets(NULL, depth);
LifeMath::float4 color = LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f);
renderer->ClearDepthStencil(depth,1.0f, 0);
renderer->SetBlendState(shadowBlendState);
}
void UpdateBuffer()
{
PSSM_CONST c;
/*float pssmSize;
float pssmNumSplits;
LifeMath::float3pssmCamPos;
LifeMath::float4x4 lmat[4];
LifeMath::float4x4 pssmMat[4];
LifeMath::float4 splitRegions[4];
LifeMath::float4 splitRegionsSm[4];*/
c.pssmSize = static_cast<float>(depthSize);
c.pssmMat[0] = lViews[0] * lProjs[0];
c.pssmMat[1] = lViews[1] * lProjs[1];
c.pssmMat[2] = lViews[2] * lProjs[2];
c.splitRegions[0] = splitRegions[0];
c.splitRegions[1] = splitRegions[1];
c.splitRegions[2] = splitRegions[2];
//printf("ololo: %i\n", sizeof(PSSM_CONST));
cbPssm->Update(&c, sizeof(PSSM_CONST));
}
void BeginSplit(int iSplit)
{
IRenderer* renderer = CG::me()->GetRenderer();
LifeMath::Rect2i scissor = LifeMath::Rect2i(0, 0, depthSize, depthSize);
renderer->SetScissorRectangle(scissor);
fNear = fSplitDistances[iSplit];
fFar = fSplitDistances[iSplit + 1];
float fScale = 1.1f;
CalculateFrustumCorners(sceneCam->getPosition(), sceneCam->getDirection(), sceneCam->getUp(),
fNear, fFar, sceneCam->getFov(), sceneCam->getAspect(), fScale, vLightTarget);
vLightSource = vLightTarget + light->getDirection() * 200.0f;
vLightTarget = vLightTarget + light->getDirection() * -50.0f;
LifeMath::float3 diff = points[6] - points[0];
//CalculateLightForFrustum(vLightTarget);
float projSize = Vec3Length(&diff);
Mat4x4LookAtLH(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f), mLightView);
Mat4x4Ortho(projSize, projSize, 0.1f, 350.0, mLightProj);
float minDist = 100000.0f;
float maxDist = 0.0f;
LifeMath::float4x4 mLightViewProj = mLightView * mLightProj;
for(int i = 0; i< 8; i++)
{
LifeMath::float4 vTransformed;
Vec3Transform(&points[i], &mLightViewProj, &vTransformed);
float dist = vTransformed.Z;
if(minDist > dist)
minDist = dist;
if(maxDist < dist)
maxDist = dist;
}
float vol = 1000.0f - 0.1f;
Mat4x4Ortho(projSize, projSize, 1.0f, maxDist * vol, mLightProj);
f.UpdateFrustum(mLightView * mLightProj);
//cam1.ViewMatrix = g_mLightView;
//cam1.ProjectionMatrix = g_mLightProj;
//cam1.Frustum = f;
//RenderQueue q = scene.CullScene(cam1, true, EffectType.SHADOW_MAPPING );
lViews[iSplit] = mLightView;
lProjs[iSplit] = mLightProj;
LifeMath::float4 region = splitRegions[iSplit];
printf("CHECK ME TOO!!!\n");
LifeMath::Rect2i tr =viewRegions[iSplit];
renderer->SetViewport(tr);
// renderer->SetViewport(splitRegions[iSplit].Region);
}
void EndSplit()
{
}
void End()
{
CG::me()->GetRenderer()->SetBlendState(restoreBlendState);
}
void CalculateSplitPlanes(const Camera* sceneCam)
{
fSplitSchemeLambda = clampf(fSplitSchemeLambda, 0.0f, 1.0f);
for (int i = 0; i < splitCount; i++)
{
float fIDM = (float)i / (float)splitCount;
float fLog = sceneCam->getNear() * pow((sceneCam->getFar() / sceneCam->getNear()), fIDM);
float fUniform = sceneCam->getNear() + (sceneCam->getFar() - sceneCam->getNear()) * fIDM;
fSplitDistances[i] = fLog * fSplitSchemeLambda + fUniform * (1.0f - fSplitSchemeLambda);
/*
float fIDM = (float)i / (float)splitCount;
float fLog = sceneCam->getNear() * pow((fLightFarMax / sceneCam->getNear()), fIDM);
float fUniform = sceneCam->getNear() + (fLightFarMax - sceneCam->getNear()) * fIDM;
fSplitDistances[i] = fLog * fSplitSchemeLambda + fUniform * (1.0f - fSplitSchemeLambda);*/
}
fSplitDistances[0] = sceneCam->getNear();
fSplitDistances[splitCount] = sceneCam->getFar();
}
void CalculateLightForFrustum(LifeMath::float3 frustumCenter)
{
// calculate standard view and projection matrices for light
CalculateViewProj(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f),
fLightFOV, fLightNear, fLightFarMax, 1.0f);
// Next we will find the min and max values of the current
// frustum split in lights post-projection space
// (where coordinate range is from -1.0 to 1.0)
//
float fMaxX = -10000000.0f;
float fMaxY = -10000000.0f;
float fMinX = 10000000.0f;
float fMinY = 10000000.0f;
float fMaxZ = 0.0f;
LifeMath::float4x4 mLightViewProj = mLightView * mLightProj;
// for each corner point
for (int i = 0; i < 8; i++)
{
// transform point
LifeMath::float4 vTransformed;
Vec3Transform(&points[i], &mLightViewProj, &vTransformed);
// project x and y
vTransformed.X /= vTransformed.W;
vTransformed.Y /= vTransformed.W;
// find min and max values
if (vTransformed.X > fMaxX) fMaxX = vTransformed.X;
if (vTransformed.Y > fMaxY) fMaxY = vTransformed.Y;
if (vTransformed.Y < fMinY) fMinY = vTransformed.Y;
if (vTransformed.X < fMinX) fMinX = vTransformed.X;
// find largest z distance
if (vTransformed.Z > fMaxZ) fMaxZ = vTransformed.Z;
}
// set values to valid range (post-projection)
fMaxX = clampf(fMaxX, -1.0f, 1.0f);
fMaxY = clampf(fMaxY, -1.0f, 1.0f);
fMinX = clampf(fMinX, -1.0f, 1.0f);
fMinY = clampf(fMinY, -1.0f, 1.0f);
// Adjust the far plane of the light to be at the farthest
// point of the frustum split. Some bias may be necessary.
//
fLightFar = fMaxZ + fLightNear + 1.5f;
//_fLightFar = fMaxZ + _fLightNear;
// re-calculate lights matrices with the new far plane
CalculateViewProj(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f),
fLightFOV, fLightNear, fLightFar, 1.0f);
// Next we build a special matrix for cropping the lights view
// to only contain points of the current frustum split
//
LifeMath::float4 vTransCenter;
Vec3Transform(&frustumCenter, &mLightViewProj, &vTransCenter);
float fScaleX = 2.0f / (fMaxX - fMinX);
float fScaleY = 2.0f / (fMaxY - fMinY);
float fOffsetX = -0.5f * (fMaxX + fMinX) * fScaleX + vTransCenter.X;
float fOffsetY = -0.5f * (fMaxY + fMinY) * fScaleY + vTransCenter.Y;
LifeMath::float4x4 mCropView;
mCropView.M11 = fScaleX; mCropView.M12 = 0.0f; mCropView.M13 = 0.0f; mCropView.M14 = 0.0f;
mCropView.M21 = 0.0f; mCropView.M22 = fScaleY; mCropView.M23 = 0.0f; mCropView.M24 = 0.0f;
mCropView.M31 = 0.0f; mCropView.M32 = 0.0f; mCropView.M33 = 1.0f; mCropView.M34 = 0.0f;
mCropView.M41 = fOffsetX; mCropView.M42 = fOffsetY; mCropView.M43 = 0.0f; mCropView.M44 = 1.0f;
// multiply the projection matrix with it
mLightProj = mLightProj * mCropView;
// finally modify projection matrix for linearized depth
mLightProj.M33 /= fLightFar;
mLightProj.M43 /= fLightFar;
}
void CalculateViewProj(LifeMath::float3 vSource, LifeMath::float3 vTarget, LifeMath::float3 vUpVector,
float fFOV, float fNear, float fFar, float fAspect)
{
Mat4x4LookAtLH(vSource, vTarget, vUpVector, mLightView);
Mat4x4PerspectiveFOV(fFOV, fAspect, fNear, fFar, mLightProj);
}
void CalculateFrustumCorners(LifeMath::float3 vSource, LifeMath::float3 vTarget,LifeMath::float3 vUp,float fNear, float fFar,
float fFOV, float fAspect, float fScale, LifeMath::float3& center)
{
vTarget = vTarget + vSource;
LifeMath::float3 vZ = vTarget - vSource;
LifeMath::Vec3Normalize(&vZ);
LifeMath::float3 vX = LifeMath::Vec3Cross(vUp, vZ);
LifeMath::Vec3Normalize(&vX);
LifeMath::float3 vY = LifeMath::Vec3Cross(vZ, vX);
float fNearPlaneHeight = tanf(fFOV * 0.5f) * fNear;
float fNearPlaneWidth = fNearPlaneHeight * fAspect;
float fFarPlaneHeight = tanf(fFOV * 0.5f) * fFar;
float fFarPlaneWidth = fFarPlaneHeight * fAspect;
LifeMath::float3 vNearPlaneCenter = vSource + vZ * fNear;
LifeMath::float3 vFarPlaneCenter = vSource + vZ * fFar;
points[0] = vNearPlaneCenter - vX * fNearPlaneWidth - vY * fNearPlaneHeight;
points[1] = vNearPlaneCenter - vX * fNearPlaneWidth + vY * fNearPlaneHeight;
points[2] = vNearPlaneCenter + vX * fNearPlaneWidth + vY * fNearPlaneHeight;
points[3] = vNearPlaneCenter + vX * fNearPlaneWidth - vY * fNearPlaneHeight;
points[4] = vFarPlaneCenter - vX * fFarPlaneWidth - vY * fFarPlaneHeight;
points[5] = vFarPlaneCenter - vX * fFarPlaneWidth + vY * fFarPlaneHeight;
points[6] = vFarPlaneCenter + vX * fFarPlaneWidth + vY * fFarPlaneHeight;
points[7] = vFarPlaneCenter + vX * fFarPlaneWidth - vY * fFarPlaneHeight;
// calculate center of points
LifeMath::float3 vCenter;
vCenter = LifeMath::float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < 8; i++) vCenter += points[i];
vCenter /= 8.0f;
// for each point
for (int i = 0; i < 8; i++)
{
// scale by adding offset from center
points[i] += (points[i] - vCenter) * (fScale - 1.0f);
}
center = vCenter;
}
};
}
#endif // passPSSM_h__
+62
View File
@@ -0,0 +1,62 @@
/**
* pugixml parser - version 1.0
* --------------------------------------------------------
* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at http://pugixml.org/
*
* This library is distributed under the MIT License. See notice at the end
* of this file.
*
* This work is based on the pugxml parser, which is:
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
*/
#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP
// Uncomment this to enable wchar_t mode
// #define PUGIXML_WCHAR_MODE
// Uncomment this to disable XPath
// #define PUGIXML_NO_XPATH
// Uncomment this to disable STL
// Note: you can't use XPath with PUGIXML_NO_STL
// #define PUGIXML_NO_STL
// Uncomment this to disable exceptions
// Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS
// #define PUGIXML_NO_EXCEPTIONS
// Set this to control attributes for public classes/functions, i.e.:
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
#endif
/**
* Copyright (c) 2006-2010 Arseny Kapoulkine
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
/*
* Boost.Foreach support for pugixml classes.
* This file is provided to the public domain.
* Written by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
*/
#ifndef HEADER_PUGIXML_FOREACH_HPP
#define HEADER_PUGIXML_FOREACH_HPP
#include "pugixml.hpp"
/*
* These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child iteration only).
* Example usage:
* BOOST_FOREACH(xml_node n, doc) {}
*/
namespace boost
{
template <typename> struct range_mutable_iterator;
template <typename> struct range_const_iterator;
template<> struct range_mutable_iterator<pugi::xml_node>
{
typedef pugi::xml_node::iterator type;
};
template<> struct range_const_iterator<pugi::xml_node>
{
typedef pugi::xml_node::iterator type;
};
template<> struct range_mutable_iterator<pugi::xml_document>
{
typedef pugi::xml_document::iterator type;
};
template<> struct range_const_iterator<pugi::xml_document>
{
typedef pugi::xml_document::iterator type;
};
}
/*
* These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child/attribute iteration).
* Example usage:
* BOOST_FOREACH(xml_node n, children(doc)) {}
* BOOST_FOREACH(xml_node n, attributes(doc)) {}
*/
namespace pugi
{
struct xml_node_children_adapter
{
typedef pugi::xml_node::iterator iterator;
typedef pugi::xml_node::iterator const_iterator;
xml_node node;
const_iterator begin() const
{
return node.begin();
}
const_iterator end() const
{
return node.end();
}
};
xml_node_children_adapter children(const pugi::xml_node& node)
{
xml_node_children_adapter result = {node};
return result;
}
struct xml_node_attribute_adapter
{
typedef pugi::xml_node::attribute_iterator iterator;
typedef pugi::xml_node::attribute_iterator const_iterator;
xml_node node;
const_iterator begin() const
{
return node.attributes_begin();
}
const_iterator end() const
{
return node.attributes_end();
}
};
xml_node_attribute_adapter attributes(const pugi::xml_node& node)
{
xml_node_attribute_adapter result = {node};
return result;
}
}
#endif
Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+205
View File
@@ -0,0 +1,205 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>pugixml 1.0</title>
<link rel="stylesheet" href="pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="manual.html" title="pugixml 1.0">
<link rel="next" href="manual/install.html" title="Installation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<b>Overview</b> |
<a href="manual/install.html">Installation</a> |
Document:
<a href="manual/dom.html">Object model</a> &middot; <a href="manual/loading.html">Loading</a> &middot; <a href="manual/access.html">Accessing</a> &middot; <a href="manual/modify.html">Modifying</a> &middot; <a href="manual/saving.html">Saving</a> |
<a href="manual/xpath.html">XPath</a> |
<a href="manual/apiref.html">API Reference</a> |
<a href="manual/toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav"><a accesskey="n" href="manual/install.html"><img src="images/next.png" alt="Next"></a></div></td>
</tr></table>
<hr>
<div class="book"><div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.overview"></a><a class="link" href="manual.html#manual.overview" title="Overview"> Overview</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="manual.html#manual.overview.introduction"> Introduction</a></span></dt>
<dt><span class="section"><a href="manual.html#manual.overview.feedback"> Feedback</a></span></dt>
<dt><span class="section"><a href="manual.html#manual.overview.thanks"> Acknowledgments</a></span></dt>
<dt><span class="section"><a href="manual.html#manual.overview.license"> License</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.overview.introduction"></a><a class="link" href="manual.html#manual.overview.introduction" title="Introduction"> Introduction</a>
</h3></div></div></div>
<p>
<a href="http://pugixml.org/" target="_top">pugixml</a> is a light-weight C++ XML
processing library. It consists of a DOM-like interface with rich traversal/modification
capabilities, an extremely fast XML parser which constructs the DOM tree
from an XML file/buffer, and an <a class="link" href="manual/xpath.html" title="XPath">XPath 1.0 implementation</a>
for complex data-driven tree queries. Full Unicode support is also available,
with <a class="link" href="manual/dom.html#manual.dom.unicode" title="Unicode interface">two Unicode interface variants</a>
and conversions between different Unicode encodings (which happen automatically
during parsing/saving). The library is <a class="link" href="manual/install.html#manual.install.portability" title="Portability">extremely
portable</a> and easy to integrate and use. pugixml is developed and maintained
since 2006 and has many users. All code is distributed under the <a class="link" href="manual.html#manual.overview.license" title="License">MIT
license</a>, making it completely free to use in both open-source and
proprietary applications.
</p>
<p>
pugixml enables very fast, convenient and memory-efficient XML document processing.
However, since pugixml has a DOM parser, it can't process XML documents that
do not fit in memory; also the parser is a non-validating one, so if you
need DTD or XML Schema validation, the library is not for you.
</p>
<p>
This is the complete manual for pugixml, which describes all features of
the library in detail. If you want to start writing code as quickly as possible,
you are advised to <a href="quickstart.html" target="_top">read the quick start guide
first</a>.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
No documentation is perfect, neither is this one. If you encounter a description
that is unclear, please file an issue as described in <a class="xref" href="manual.html#manual.overview.feedback" title="Feedback"> Feedback</a>.
Also if you can spare the time for a full proof-reading, including spelling
and grammar, that would be great! Please <a class="link" href="manual.html#email">send me
an e-mail</a>; as a token of appreciation, your name will be included
into the <a class="link" href="manual.html#manual.overview.thanks" title="Acknowledgments">corresponding section</a>
of this documentation.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.overview.feedback"></a><a class="link" href="manual.html#manual.overview.feedback" title="Feedback"> Feedback</a>
</h3></div></div></div>
<p>
If you believe you've found a bug in pugixml (bugs include compilation problems
(errors/warnings), crashes, performance degradation and incorrect behavior),
please file an issue via <a href="http://code.google.com/p/pugixml/issues/entry" target="_top">issue
submission form</a>. Be sure to include the relevant information so that
the bug can be reproduced: the version of pugixml, compiler version and target
architecture, the code that uses pugixml and exhibits the bug, etc.
</p>
<p>
Feature requests can be reported the same way as bugs, so if you're missing
some functionality in pugixml or if the API is rough in some places and you
can suggest an improvement, <a href="http://code.google.com/p/pugixml/issues/entry?template=Feature%20request" target="_top">file
an issue</a>. However please note that there are many factors when considering
API changes (compatibility with previous versions, API redundancy, etc.),
so generally features that can be implemented via a small function without
pugixml modification are not accepted. However, all rules have exceptions.
</p>
<p>
If you have a contribution to pugixml, such as build script for some build
system/IDE, or a well-designed set of helper functions, or a binding to some
language other than C++, please <a href="http://code.google.com/p/pugixml/issues/entry?template=Feature%20request" target="_top">file
an issue</a>. You can include the relevant patches as issue attachments.
Your contribution has to be distributed under the terms of a license that's
compatible with pugixml license; i.e. GPL/LGPL licensed code is not accepted.
</p>
<a name="email"></a><p>
If filing an issue is not possible due to privacy or other concerns, you
can contact pugixml author by e-mail directly: <a href="mailto:arseny.kapoulkine@gmail.com" target="_top">arseny.kapoulkine@gmail.com</a>.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.overview.thanks"></a><a class="link" href="manual.html#manual.overview.thanks" title="Acknowledgments"> Acknowledgments</a>
</h3></div></div></div>
<p>
pugixml could not be developed without the help from many people; some of
them are listed in this section. If you've played a part in pugixml development
and you can not find yourself on this list, I'm truly sorry; please <a class="link" href="manual.html#email">send me an e-mail</a> so I can fix this.
</p>
<p>
Thanks to <span class="bold"><strong>Kristen Wegner</strong></span> for pugxml parser,
which was used as a basis for pugixml.
</p>
<p>
Thanks to <span class="bold"><strong>Neville Franks</strong></span> for contributions
to pugxml parser.
</p>
<p>
Thanks to <span class="bold"><strong>Artyom Palvelev</strong></span> for suggesting
a lazy gap contraction approach.
</p>
<p>
Thanks to <span class="bold"><strong>Vyacheslav Egorov</strong></span> for documentation
proofreading.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.overview.license"></a><a class="link" href="manual.html#manual.overview.license" title="License"> License</a>
</h3></div></div></div>
<p>
The pugixml library is distributed under the MIT license:
</p>
<div class="blockquote"><blockquote class="blockquote">
<p>
Copyright (c) 2006-2010 Arseny Kapoulkine
</p>
<p>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
</p>
<p>
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
</p>
</blockquote></div>
<p>
This means that you can freely use pugixml in your applications, both open-source
and proprietary. If you use pugixml in a product, it is sufficient to add
an acknowledgment like this to the product distribution:
</p>
<div class="blockquote"><blockquote class="blockquote"><p>
This software is based on pugixml library (http://pugixml.org).<br>
pugixml
is Copyright (C) 2006-2010 Arseny Kapoulkine.
</p></blockquote></div>
</div>
</div></div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: October 31, 2010 at 17:44:02 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<b>Overview</b> |
<a href="manual/install.html">Installation</a> |
Document:
<a href="manual/dom.html">Object model</a> &middot; <a href="manual/loading.html">Loading</a> &middot; <a href="manual/access.html">Accessing</a> &middot; <a href="manual/modify.html">Modifying</a> &middot; <a href="manual/saving.html">Saving</a> |
<a href="manual/xpath.html">XPath</a> |
<a href="manual/apiref.html">API Reference</a> |
<a href="manual/toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav"><a accesskey="n" href="manual/install.html"><img src="images/next.png" alt="Next"></a></div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,723 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Accessing document data</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="loading.html" title="Loading document">
<link rel="next" href="modify.html" title="Modifying document data">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <b>Accessing</b> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="loading.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="modify.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.access"></a><a class="link" href="access.html" title="Accessing document data"> Accessing document data</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="access.html#manual.access.basic"> Basic traversal functions</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.nodedata"> Getting node data</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.attrdata"> Getting attribute data</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.contents"> Contents-based traversal functions</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.iterators"> Traversing node/attribute lists
via iterators</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.walker"> Recursive traversal with xml_tree_walker</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.predicate"> Searching for nodes/attributes
with predicates</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.misc"> Miscellaneous functions</a></span></dt>
</dl></div>
<p>
pugixml features an extensive interface for getting various types of data from
the document and for traversing the document. This section provides documentation
for all such functions that do not modify the tree except for XPath-related
functions; see <a class="xref" href="xpath.html" title="XPath"> XPath</a> for XPath reference. As discussed in <a class="xref" href="dom.html#manual.dom.cpp" title="C++ interface"> C++ interface</a>,
there are two types of handles to tree data - <a class="link" href="dom.html#xml_node">xml_node</a>
and <a class="link" href="dom.html#xml_attribute">xml_attribute</a>. The handles have special
null (empty) values which propagate through various functions and thus are
useful for writing more concise code; see <a class="link" href="dom.html#node_null">this description</a>
for details. The documentation in this section will explicitly state the results
of all function in case of null inputs.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.basic"></a><a class="link" href="access.html#manual.access.basic" title="Basic traversal functions"> Basic traversal functions</a>
</h3></div></div></div>
<a name="xml_node::parent"></a><a name="xml_node::first_child"></a><a name="xml_node::last_child"></a><a name="xml_node::next_sibling"></a><a name="xml_node::previous_sibling"></a><a name="xml_node::first_attribute"></a><a name="xml_node::last_attribute"></a><a name="xml_attribute::next_attribute"></a><a name="xml_attribute::previous_attribute"></a><p>
The internal representation of the document is a tree, where each node has
a list of child nodes (the order of children corresponds to their order in
the XML representation), and additionally element nodes have a list of attributes,
which is also ordered. Several functions are provided in order to let you
get from one node in the tree to the other. These functions roughly correspond
to the internal representation, and thus are usually building blocks for
other methods of traversing (i.e. XPath traversals are based on these functions).
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">parent</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">first_child</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">last_child</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">next_sibling</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">previous_sibling</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">first_attribute</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">last_attribute</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">next_attribute</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">previous_attribute</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">parent</span></code> function returns the
node's parent; all non-null nodes except the document have non-null parent.
<code class="computeroutput"><span class="identifier">first_child</span></code> and <code class="computeroutput"><span class="identifier">last_child</span></code> return the first and last child
of the node, respectively; note that only document nodes and element nodes
can have non-empty child node list. If node has no children, both functions
return null nodes. <code class="computeroutput"><span class="identifier">next_sibling</span></code>
and <code class="computeroutput"><span class="identifier">previous_sibling</span></code> return
the node that's immediately to the right/left of this node in the children
list, respectively - for example, in <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;&lt;</span><span class="identifier">b</span><span class="special">/&gt;&lt;</span><span class="identifier">c</span><span class="special">/&gt;</span></code>,
calling <code class="computeroutput"><span class="identifier">next_sibling</span></code> for
a handle that points to <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">b</span><span class="special">/&gt;</span></code>
results in a handle pointing to <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">c</span><span class="special">/&gt;</span></code>,
and calling <code class="computeroutput"><span class="identifier">previous_sibling</span></code>
results in handle pointing to <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;</span></code>.
If node does not have next/previous sibling (this happens if it is the last/first
node in the list, respectively), the functions return null nodes. <code class="computeroutput"><span class="identifier">first_attribute</span></code>, <code class="computeroutput"><span class="identifier">last_attribute</span></code>,
<code class="computeroutput"><span class="identifier">next_attribute</span></code> and <code class="computeroutput"><span class="identifier">previous_attribute</span></code> functions behave similarly
to the corresponding child node functions and allow to iterate through attribute
list in the same way.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Because of memory consumption reasons, attributes do not have a link to
their parent nodes. Thus there is no <code class="computeroutput"><span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">parent</span><span class="special">()</span></code> function.
</p></td></tr>
</table></div>
<p>
Calling any of the functions above on the null handle results in a null handle
- i.e. <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">().</span><span class="identifier">next_sibling</span><span class="special">()</span></code>
returns the second child of <code class="computeroutput"><span class="identifier">node</span></code>,
and null handle if <code class="computeroutput"><span class="identifier">node</span></code> is
null, has no children at all or if it has only one child node.
</p>
<p>
With these functions, you can iterate through all child nodes and display
all attributes like this (<a href="../samples/traverse_base.cpp" target="_top">samples/traverse_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">();</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">())</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool:"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">first_attribute</span><span class="special">();</span> <span class="identifier">attr</span><span class="special">;</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">next_attribute</span><span class="special">())</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"="</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.nodedata"></a><a class="link" href="access.html#manual.access.nodedata" title="Getting node data"> Getting node data</a>
</h3></div></div></div>
<a name="xml_node::name"></a><a name="xml_node::value"></a><p>
Apart from structural information (parent, child nodes, attributes), nodes
can have name and value, both of which are strings. Depending on node type,
name or value may be absent. <a class="link" href="dom.html#node_document">node_document</a>
nodes do not have a name or value, <a class="link" href="dom.html#node_element">node_element</a>
and <a class="link" href="dom.html#node_declaration">node_declaration</a> nodes always
have a name but never have a value, <a class="link" href="dom.html#node_pcdata">node_pcdata</a>,
<a class="link" href="dom.html#node_cdata">node_cdata</a>, <a class="link" href="dom.html#node_comment">node_comment</a>
and <a class="link" href="dom.html#node_doctype">node_doctype</a> nodes never have a name
but always have a value (it may be empty though), <a class="link" href="dom.html#node_pi">node_pi</a>
nodes always have a name and a value (again, value may be empty). In order
to get node's name or value, you can use the following functions:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">name</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
In case node does not have a name or value or if the node handle is null,
both functions return empty strings - they never return null pointers.
</p>
<a name="xml_node::child_value"></a><p>
It is common to store data as text contents of some node - i.e. <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;&lt;</span><span class="identifier">description</span><span class="special">&gt;</span><span class="identifier">This</span> <span class="identifier">is</span> <span class="identifier">a</span> <span class="identifier">node</span><span class="special">&lt;/</span><span class="identifier">description</span><span class="special">&gt;&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span></code>.
In this case, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">description</span><span class="special">&gt;</span></code> node does not have a value, but instead
has a child of type <a class="link" href="dom.html#node_pcdata">node_pcdata</a> with value
<code class="computeroutput"><span class="string">"This is a node"</span></code>. pugixml
provides two helper functions to parse such data:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">child_value</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">child_value</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">child_value</span><span class="special">()</span></code>
returns the value of the first child with type <a class="link" href="dom.html#node_pcdata">node_pcdata</a>
or <a class="link" href="dom.html#node_cdata">node_cdata</a>; <code class="computeroutput"><span class="identifier">child_value</span><span class="special">(</span><span class="identifier">name</span><span class="special">)</span></code>
is a simple wrapper for <code class="computeroutput"><span class="identifier">child</span><span class="special">(</span><span class="identifier">name</span><span class="special">).</span><span class="identifier">child_value</span><span class="special">()</span></code>.
For the above example, calling <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"description"</span><span class="special">)</span></code> and <code class="computeroutput"><span class="identifier">description</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">()</span></code> will both produce string <code class="computeroutput"><span class="string">"This is a node"</span></code>. If there is no
child with relevant type, or if the handle is null, <code class="computeroutput"><span class="identifier">child_value</span></code>
functions return empty string.
</p>
<p>
There is an example of using some of these functions <a class="link" href="access.html#code_traverse_base_data">at
the end of the next section</a>.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.attrdata"></a><a class="link" href="access.html#manual.access.attrdata" title="Getting attribute data"> Getting attribute data</a>
</h3></div></div></div>
<a name="xml_attribute::name"></a><a name="xml_attribute::value"></a><p>
All attributes have name and value, both of which are strings (value may
be empty). There are two corresponding accessors, like for <code class="computeroutput"><span class="identifier">xml_node</span></code>:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">name</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
In case the attribute handle is null, both functions return empty strings
- they never return null pointers.
</p>
<a name="xml_attribute::as_int"></a><a name="xml_attribute::as_uint"></a><a name="xml_attribute::as_double"></a><a name="xml_attribute::as_float"></a><a name="xml_attribute::as_bool"></a><p>
In many cases attribute values have types that are not strings - i.e. an
attribute may always contain values that should be treated as integers, despite
the fact that they are represented as strings in XML. pugixml provides several
accessors that convert attribute value to some other type:
</p>
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">as_int</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">as_uint</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">double</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">as_double</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">float</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">as_float</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">as_bool</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">as_int</span></code>, <code class="computeroutput"><span class="identifier">as_uint</span></code>,
<code class="computeroutput"><span class="identifier">as_double</span></code> and <code class="computeroutput"><span class="identifier">as_float</span></code> convert attribute values to numbers.
If attribute handle is null or attribute value is empty, <code class="computeroutput"><span class="number">0</span></code>
is returned. Otherwise, all leading whitespace characters are truncated,
and the remaining string is parsed as a decimal number (<code class="computeroutput"><span class="identifier">as_int</span></code>
or <code class="computeroutput"><span class="identifier">as_uint</span></code>) or as a floating
point number in either decimal or scientific form (<code class="computeroutput"><span class="identifier">as_double</span></code>
or <code class="computeroutput"><span class="identifier">as_float</span></code>). Any extra characters
are silently discarded, i.e. <code class="computeroutput"><span class="identifier">as_int</span></code>
will return <code class="computeroutput"><span class="number">1</span></code> for string <code class="computeroutput"><span class="string">"1abc"</span></code>.
</p>
<p>
In case the input string contains a number that is out of the target numeric
range, the result is undefined.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
Number conversion functions depend on current C locale as set with <code class="computeroutput"><span class="identifier">setlocale</span></code>, so may return unexpected results
if the locale is different from <code class="computeroutput"><span class="string">"C"</span></code>.
</p></td></tr>
</table></div>
<p>
<code class="computeroutput"><span class="identifier">as_bool</span></code> converts attribute
value to boolean as follows: if attribute handle is null or attribute value
is empty, <code class="computeroutput"><span class="keyword">false</span></code> is returned.
Otherwise, <code class="computeroutput"><span class="keyword">true</span></code> is returned
if the first character is one of <code class="computeroutput"><span class="char">'1'</span><span class="special">,</span> <span class="char">'t'</span><span class="special">,</span>
<span class="char">'T'</span><span class="special">,</span> <span class="char">'y'</span><span class="special">,</span> <span class="char">'Y'</span></code>.
This means that strings like <code class="computeroutput"><span class="string">"true"</span></code>
and <code class="computeroutput"><span class="string">"yes"</span></code> are recognized
as <code class="computeroutput"><span class="keyword">true</span></code>, while strings like
<code class="computeroutput"><span class="string">"false"</span></code> and <code class="computeroutput"><span class="string">"no"</span></code> are recognized as <code class="computeroutput"><span class="keyword">false</span></code>. For more complex matching you'll have
to write your own function.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
There are no portable 64-bit types in C++, so there is no corresponding
conversion function. If your platform has a 64-bit integer, you can easily
write a conversion function yourself.
</p></td></tr>
</table></div>
<a name="code_traverse_base_data"></a><p>
This is an example of using these functions, along with node data retrieval
ones (<a href="../samples/traverse_base.cpp" target="_top">samples/traverse_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">))</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">": AllowRemote "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"AllowRemote"</span><span class="special">).</span><span class="identifier">as_bool</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", Timeout "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Timeout"</span><span class="special">).</span><span class="identifier">as_int</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", Description '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"Description"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.contents"></a><a class="link" href="access.html#manual.access.contents" title="Contents-based traversal functions"> Contents-based traversal functions</a>
</h3></div></div></div>
<a name="xml_node::child"></a><a name="xml_node::attribute"></a><a name="xml_node::next_sibling_name"></a><a name="xml_node::previous_sibling_name"></a><p>
Since a lot of document traversal consists of finding the node/attribute
with the correct name, there are special functions for that purpose:
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">child</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">previous_sibling</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">child</span></code> and <code class="computeroutput"><span class="identifier">attribute</span></code>
return the first child/attribute with the specified name; <code class="computeroutput"><span class="identifier">next_sibling</span></code>
and <code class="computeroutput"><span class="identifier">previous_sibling</span></code> return
the first sibling in the corresponding direction with the specified name.
All string comparisons are case-sensitive. In case the node handle is null
or there is no node/attribute with the specified name, null handle is returned.
</p>
<p>
<code class="computeroutput"><span class="identifier">child</span></code> and <code class="computeroutput"><span class="identifier">next_sibling</span></code>
functions can be used together to loop through all child nodes with the desired
name like this:
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">))</span>
</pre>
<a name="xml_node::find_child_by_attribute"></a><p>
Occasionally the needed node is specified not by the unique name but instead
by the value of some attribute; for example, it is common to have node collections
with each node having a unique id: <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">group</span><span class="special">&gt;&lt;</span><span class="identifier">item</span> <span class="identifier">id</span><span class="special">=</span><span class="string">"1"</span><span class="special">/&gt;</span> <span class="special">&lt;</span><span class="identifier">item</span> <span class="identifier">id</span><span class="special">=</span><span class="string">"2"</span><span class="special">/&gt;&lt;/</span><span class="identifier">group</span><span class="special">&gt;</span></code>. There are two functions for finding
child nodes based on the attribute values:
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">attr_name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">attr_value</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">attr_name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">attr_value</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
The three-argument function returns the first child node with the specified
name which has an attribute with the specified name/value; the two-argument
function skips the name test for the node, which can be useful for searching
in heterogeneous collections. If the node handle is null or if no node is
found, null handle is returned. All string comparisons are case-sensitive.
</p>
<p>
In all of the above functions, all arguments have to be valid strings; passing
null pointers results in undefined behavior.
</p>
<p>
This is an example of using these functions (<a href="../samples/traverse_base.cpp" target="_top">samples/traverse_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool for *.dae generation: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">,</span> <span class="string">"OutputFileMasks"</span><span class="special">,</span> <span class="string">"*.dae"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">))</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.iterators"></a><a class="link" href="access.html#manual.access.iterators" title="Traversing node/attribute lists via iterators"> Traversing node/attribute lists
via iterators</a>
</h3></div></div></div>
<a name="xml_node_iterator"></a><a name="xml_attribute_iterator"></a><a name="xml_node::begin"></a><a name="xml_node::end"></a><a name="xml_node::attributes_begin"></a><a name="xml_node::attributes_end"></a><p>
Child node lists and attribute lists are simply double-linked lists; while
you can use <code class="computeroutput"><span class="identifier">previous_sibling</span></code>/<code class="computeroutput"><span class="identifier">next_sibling</span></code> and other such functions for
iteration, pugixml additionally provides node and attribute iterators, so
that you can treat nodes as containers of other nodes or attributes:
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">xml_node_iterator</span><span class="special">;</span>
<span class="keyword">class</span> <span class="identifier">xml_attribute_iterator</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">xml_node_iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">iterator</span><span class="special">;</span>
<span class="identifier">iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">typedef</span> <span class="identifier">xml_attribute_iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">attribute_iterator</span><span class="special">;</span>
<span class="identifier">attribute_iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">attributes_begin</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">attribute_iterator</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">attributes_end</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">begin</span></code> and <code class="computeroutput"><span class="identifier">attributes_begin</span></code>
return iterators that point to the first node/attribute, respectively; <code class="computeroutput"><span class="identifier">end</span></code> and <code class="computeroutput"><span class="identifier">attributes_end</span></code>
return past-the-end iterator for node/attribute list, respectively - this
iterator can't be dereferenced, but decrementing it results in an iterator
pointing to the last element in the list (except for empty lists, where decrementing
past-the-end iterator results in undefined behavior). Past-the-end iterator
is commonly used as a termination value for iteration loops (see sample below).
If you want to get an iterator that points to an existing handle, you can
construct the iterator with the handle as a single constructor argument,
like so: <code class="computeroutput"><span class="identifier">xml_node_iterator</span><span class="special">(</span><span class="identifier">node</span><span class="special">)</span></code>.
For <code class="computeroutput"><span class="identifier">xml_attribute_iterator</span></code>,
you'll have to provide both an attribute and its parent node.
</p>
<p>
<code class="computeroutput"><span class="identifier">begin</span></code> and <code class="computeroutput"><span class="identifier">end</span></code>
return equal iterators if called on null node; such iterators can't be dereferenced.
<code class="computeroutput"><span class="identifier">attributes_begin</span></code> and <code class="computeroutput"><span class="identifier">attributes_end</span></code> behave the same way. For
correct iterator usage this means that child node/attribute collections of
null nodes appear to be empty.
</p>
<p>
Both types of iterators have bidirectional iterator semantics (i.e. they
can be incremented and decremented, but efficient random access is not supported)
and support all usual iterator operations - comparison, dereference, etc.
The iterators are invalidated if the node/attribute objects they're pointing
to are removed from the tree; adding nodes/attributes does not invalidate
any iterators.
</p>
<p>
Here is an example of using iterators for document traversal (<a href="../samples/traverse_iter.cpp" target="_top">samples/traverse_iter.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node_iterator</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> <span class="identifier">it</span> <span class="special">!=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">it</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool:"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute_iterator</span> <span class="identifier">ait</span> <span class="special">=</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">attributes_begin</span><span class="special">();</span> <span class="identifier">ait</span> <span class="special">!=</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">attributes_end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">ait</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">ait</span><span class="special">-&gt;</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"="</span> <span class="special">&lt;&lt;</span> <span class="identifier">ait</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
Node and attribute iterators are somewhere in the middle between const
and non-const iterators. While dereference operation yields a non-constant
reference to the object, so that you can use it for tree modification operations,
modifying this reference by assignment - i.e. passing iterators to a function
like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">sort</span></code> - will not give expected results,
as assignment modifies local handle that's stored in the iterator.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.walker"></a><a class="link" href="access.html#manual.access.walker" title="Recursive traversal with xml_tree_walker"> Recursive traversal with xml_tree_walker</a>
</h3></div></div></div>
<a name="xml_tree_walker"></a><p>
The methods described above allow traversal of immediate children of some
node; if you want to do a deep tree traversal, you'll have to do it via a
recursive function or some equivalent method. However, pugixml provides a
helper for depth-first traversal of a subtree. In order to use it, you have
to implement <code class="computeroutput"><span class="identifier">xml_tree_walker</span></code>
interface and to call <code class="computeroutput"><span class="identifier">traverse</span></code>
function:
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">xml_tree_walker</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="identifier">begin</span><span class="special">(</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="identifier">for_each</span><span class="special">(</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="identifier">end</span><span class="special">(</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">depth</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">traverse</span><span class="special">(</span><span class="identifier">xml_tree_walker</span><span class="special">&amp;</span> <span class="identifier">walker</span><span class="special">);</span>
</pre>
<a name="xml_tree_walker::begin"></a><a name="xml_tree_walker::for_each"></a><a name="xml_tree_walker::end"></a><a name="xml_node::traverse"></a><p>
The traversal is launched by calling <code class="computeroutput"><span class="identifier">traverse</span></code>
function on traversal root and proceeds as follows:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
First, <code class="computeroutput"><span class="identifier">begin</span></code> function
is called with traversal root as its argument.
</li>
<li class="listitem">
Then, <code class="computeroutput"><span class="identifier">for_each</span></code> function
is called for all nodes in the traversal subtree in depth first order,
excluding the traversal root. Node is passed as an argument.
</li>
<li class="listitem">
Finally, <code class="computeroutput"><span class="identifier">end</span></code> function
is called with traversal root as its argument.
</li>
</ul></div>
<p>
If <code class="computeroutput"><span class="identifier">begin</span></code>, <code class="computeroutput"><span class="identifier">end</span></code>
or any of the <code class="computeroutput"><span class="identifier">for_each</span></code> calls
return <code class="computeroutput"><span class="keyword">false</span></code>, the traversal
is terminated and <code class="computeroutput"><span class="keyword">false</span></code> is returned
as the traversal result; otherwise, the traversal results in <code class="computeroutput"><span class="keyword">true</span></code>. Note that you don't have to override
<code class="computeroutput"><span class="identifier">begin</span></code> or <code class="computeroutput"><span class="identifier">end</span></code>
functions; their default implementations return <code class="computeroutput"><span class="keyword">true</span></code>.
</p>
<a name="xml_tree_walker::depth"></a><p>
You can get the node's depth relative to the traversal root at any point
by calling <code class="computeroutput"><span class="identifier">depth</span></code> function.
It returns <code class="computeroutput"><span class="special">-</span><span class="number">1</span></code>
if called from <code class="computeroutput"><span class="identifier">begin</span></code>/<code class="computeroutput"><span class="identifier">end</span></code>, and returns 0-based depth if called
from <code class="computeroutput"><span class="identifier">for_each</span></code> - depth is
0 for all children of the traversal root, 1 for all grandchildren and so
on.
</p>
<p>
This is an example of traversing tree hierarchy with xml_tree_walker (<a href="../samples/traverse_walker.cpp" target="_top">samples/traverse_walker.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">simple_walker</span><span class="special">:</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_tree_walker</span>
<span class="special">{</span>
<span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="identifier">for_each</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special">&lt;</span> <span class="identifier">depth</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span> <span class="comment">// indentation
</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node_types</span><span class="special">[</span><span class="identifier">node</span><span class="special">.</span><span class="identifier">type</span><span class="special">()]</span> <span class="special">&lt;&lt;</span> <span class="string">": name='"</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"', value='"</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span> <span class="comment">// continue traversal
</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">simple_walker</span> <span class="identifier">walker</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">traverse</span><span class="special">(</span><span class="identifier">walker</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.predicate"></a><a class="link" href="access.html#manual.access.predicate" title="Searching for nodes/attributes with predicates"> Searching for nodes/attributes
with predicates</a>
</h3></div></div></div>
<a name="xml_node::find_attribute"></a><a name="xml_node::find_child"></a><a name="xml_node::find_node"></a><p>
While there are existing functions for getting a node/attribute with known
contents, they are often not sufficient for simple queries. As an alternative
for manual iteration through nodes/attributes until the needed one is found,
you can make a predicate and call one of <code class="computeroutput"><span class="identifier">find_</span></code>
functions:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Predicate</span><span class="special">&gt;</span> <span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">find_attribute</span><span class="special">(</span><span class="identifier">Predicate</span> <span class="identifier">pred</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Predicate</span><span class="special">&gt;</span> <span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">find_child</span><span class="special">(</span><span class="identifier">Predicate</span> <span class="identifier">pred</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Predicate</span><span class="special">&gt;</span> <span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">find_node</span><span class="special">(</span><span class="identifier">Predicate</span> <span class="identifier">pred</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
The predicate should be either a plain function or a function object which
accepts one argument of type <code class="computeroutput"><span class="identifier">xml_attribute</span></code>
(for <code class="computeroutput"><span class="identifier">find_attribute</span></code>) or
<code class="computeroutput"><span class="identifier">xml_node</span></code> (for <code class="computeroutput"><span class="identifier">find_child</span></code> and <code class="computeroutput"><span class="identifier">find_node</span></code>),
and returns <code class="computeroutput"><span class="keyword">bool</span></code>. The predicate
is never called with null handle as an argument.
</p>
<p>
<code class="computeroutput"><span class="identifier">find_attribute</span></code> function iterates
through all attributes of the specified node, and returns the first attribute
for which the predicate returned <code class="computeroutput"><span class="keyword">true</span></code>.
If the predicate returned <code class="computeroutput"><span class="keyword">false</span></code>
for all attributes or if there were no attributes (including the case where
the node is null), null attribute is returned.
</p>
<p>
<code class="computeroutput"><span class="identifier">find_child</span></code> function iterates
through all child nodes of the specified node, and returns the first node
for which the predicate returned <code class="computeroutput"><span class="keyword">true</span></code>.
If the predicate returned <code class="computeroutput"><span class="keyword">false</span></code>
for all nodes or if there were no child nodes (including the case where the
node is null), null node is returned.
</p>
<p>
<code class="computeroutput"><span class="identifier">find_node</span></code> function performs
a depth-first traversal through the subtree of the specified node (excluding
the node itself), and returns the first node for which the predicate returned
<code class="computeroutput"><span class="keyword">true</span></code>. If the predicate returned
<code class="computeroutput"><span class="keyword">false</span></code> for all nodes or if subtree
was empty, null node is returned.
</p>
<p>
This is an example of using predicate-based functions (<a href="../samples/traverse_predicate.cpp" target="_top">samples/traverse_predicate.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">small_timeout</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Timeout"</span><span class="special">).</span><span class="identifier">as_int</span><span class="special">()</span> <span class="special">&lt;</span> <span class="number">20</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">struct</span> <span class="identifier">allow_remote_predicate</span>
<span class="special">{</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">attr</span><span class="special">)</span> <span class="keyword">const</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">strcmp</span><span class="special">(</span><span class="identifier">attr</span><span class="special">.</span><span class="identifier">name</span><span class="special">(),</span> <span class="string">"AllowRemote"</span><span class="special">)</span> <span class="special">==</span> <span class="number">0</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span><span class="special">)</span> <span class="keyword">const</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"AllowRemote"</span><span class="special">).</span><span class="identifier">as_bool</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Find child via predicate (looks for direct children only)
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">find_child</span><span class="special">(</span><span class="identifier">allow_remote_predicate</span><span class="special">()).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// Find node via predicate (looks for all descendants in depth-first order)
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">find_node</span><span class="special">(</span><span class="identifier">allow_remote_predicate</span><span class="special">()).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// Find attribute via predicate
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">find_attribute</span><span class="special">(</span><span class="identifier">allow_remote_predicate</span><span class="special">()).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// We can use simple functions instead of function objects
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">find_child</span><span class="special">(</span><span class="identifier">small_timeout</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.access.misc"></a><a class="link" href="access.html#manual.access.misc" title="Miscellaneous functions"> Miscellaneous functions</a>
</h3></div></div></div>
<a name="xml_node::root"></a><p>
If you need to get the document root of some node, you can use the following
function:
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">root</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
This function returns the node with type <a class="link" href="dom.html#node_document">node_document</a>,
which is the root node of the document the node belongs to (unless the node
is null, in which case null node is returned).
</p>
<a name="xml_node::path"></a><a name="xml_node::first_element_by_path"></a><p>
While pugixml supports complex XPath expressions, sometimes a simple path
handling facility is needed. There are two functions, for getting node path
and for converting path to a node:
</p>
<pre class="programlisting"><span class="identifier">string_t</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">path</span><span class="special">(</span><span class="identifier">char_t</span> <span class="identifier">delimiter</span> <span class="special">=</span> <span class="char">'/'</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">first_element_by_path</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">path</span><span class="special">,</span> <span class="identifier">char_t</span> <span class="identifier">delimiter</span> <span class="special">=</span> <span class="char">'/'</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
Node paths consist of node names, separated with a delimiter (which is <code class="computeroutput"><span class="special">/</span></code> by default); also paths can contain self
(<code class="computeroutput"><span class="special">.</span></code>) and parent (<code class="computeroutput"><span class="special">..</span></code>) pseudo-names, so that this is a valid
path: <code class="computeroutput"><span class="string">"../../foo/./bar"</span></code>.
<code class="computeroutput"><span class="identifier">path</span></code> returns the path to
the node from the document root, <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
looks for a node represented by a given path; a path can be an absolute one
(absolute paths start with the delimiter), in which case the rest of the
path is treated as document root relative, and relative to the given node.
For example, in the following document: <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">&gt;&lt;</span><span class="identifier">b</span><span class="special">&gt;&lt;</span><span class="identifier">c</span><span class="special">/&gt;&lt;/</span><span class="identifier">b</span><span class="special">&gt;&lt;/</span><span class="identifier">a</span><span class="special">&gt;</span></code>,
node <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">c</span><span class="special">/&gt;</span></code> has path <code class="computeroutput"><span class="string">"a/b/c"</span></code>;
calling <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
for document with path <code class="computeroutput"><span class="string">"a/b"</span></code>
results in node <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">b</span><span class="special">/&gt;</span></code>; calling <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
for node <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;</span></code> with path <code class="computeroutput"><span class="string">"../a/./b/../."</span></code>
results in node <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;</span></code>; calling <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
with path <code class="computeroutput"><span class="string">"/a"</span></code> results
in node <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;</span></code> for any node.
</p>
<p>
In case path component is ambiguous (if there are two nodes with given name),
the first one is selected; paths are not guaranteed to uniquely identify
nodes in a document. If any component of a path is not found, the result
of <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
is null node; also <code class="computeroutput"><span class="identifier">first_element_by_path</span></code>
returns null node for null nodes, in which case the path does not matter.
<code class="computeroutput"><span class="identifier">path</span></code> returns an empty string
for null nodes.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
<code class="computeroutput"><span class="identifier">path</span></code> function returns the
result as STL string, and thus is not available if <a class="link" href="install.html#PUGIXML_NO_STL">PUGIXML_NO_STL</a>
is defined.
</p></td></tr>
</table></div>
<a name="xml_node::offset_debug"></a><p>
pugixml does not record row/column information for nodes upon parsing for
efficiency reasons. However, if the node has not changed in a significant
way since parsing (the name/value are not changed, and the node itself is
the original one, i.e. it was not deleted from the tree and re-added later),
it is possible to get the offset from the beginning of XML buffer:
</p>
<pre class="programlisting"><span class="identifier">ptrdiff_t</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">offset_debug</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
If the offset is not available (this happens if the node is null, was not
originally parsed from a stream, or has changed in a significant way), the
function returns -1. Otherwise it returns the offset to node's data from
the beginning of XML buffer in <a class="link" href="dom.html#char_t">pugi::char_t</a>
units. For more information on parsing offsets, see <a class="link" href="loading.html#xml_parse_result::offset">parsing
error handling documentation</a>.
</p>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <b>Accessing</b> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="loading.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="modify.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,785 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Changelog</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="xpath.html" title="XPath">
<link rel="next" href="apiref.html" title="API Reference">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="xpath.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="apiref.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.changes"></a><a class="link" href="changes.html" title="Changelog"> Changelog</a>
</h2></div></div></div>
<a name="manual.changes.1_11_2010___version_1_0"></a><h6>
<a class="link" href="changes.html#manual.changes.1_11_2010___version_1_0">1.11.2010 - version
1.0</a>
</h6>
<p>
Major release, featuring many XPath enhancements, wide character filename support,
miscellaneous performance improvements, bug fixes and more.
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
XPath:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
XPath implementation is moved to pugixml.cpp (which is the only source
file now); use PUGIXML_NO_XPATH if you want to disable XPath to reduce
code size
</li>
<li class="listitem">
XPath is now supported without exceptions (PUGIXML_NO_EXCEPTIONS);
the error handling mechanism depends on the presence of exception
support
</li>
<li class="listitem">
XPath is now supported without STL (PUGIXML_NO_STL)
</li>
<li class="listitem">
Introduced variable support
</li>
<li class="listitem">
Introduced new xpath_query::evaluate_string, which works without
STL
</li>
<li class="listitem">
Introduced new xpath_node_set constructor (from an iterator range)
</li>
<li class="listitem">
Evaluation function now accept attribute context nodes
</li>
<li class="listitem">
All internal allocations use custom allocation functions
</li>
<li class="listitem">
Improved error reporting; now a last parsed offset is returned together
with the parsing error
</li>
</ol></div>
</li>
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed memory leak for loading from streams with stream exceptions
turned on
</li>
<li class="listitem">
Fixed custom deallocation function calling with null pointer in one
case
</li>
<li class="listitem">
Fixed missing attributes for iterator category functions; all functions/classes
can now be DLL-exported
</li>
<li class="listitem">
Worked around Digital Mars compiler bug, which lead to minor read
overfetches in several functions
</li>
<li class="listitem">
load_file now works with 2+ Gb files in MSVC/MinGW
</li>
<li class="listitem">
XPath: fixed memory leaks for incorrect queries
</li>
<li class="listitem">
XPath: fixed xpath_node() attribute constructor with empty attribute
argument
</li>
<li class="listitem">
XPath: fixed lang() function for non-ASCII arguments
</li>
</ol></div>
</li>
<li class="listitem">
Specification changes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
CDATA nodes containing ]]&gt; are printed as several nodes; while
this changes the internal structure, this is the only way to escape
CDATA contents
</li>
<li class="listitem">
Memory allocation errors during parsing now preserve last parsed
offset (to give an idea about parsing progress)
</li>
<li class="listitem">
If an element node has the only child, and it is of CDATA type, then
the extra indentation is omitted (previously this behavior only held
for PCDATA children)
</li>
</ol></div>
</li>
<li class="listitem">
Additional functionality:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Added xml_parse_result default constructor
</li>
<li class="listitem">
Added xml_document::load_file and xml_document::save_file with wide
character paths
</li>
<li class="listitem">
Added as_utf8 and as_wide overloads for std::wstring/std::string
arguments
</li>
<li class="listitem">
Added DOCTYPE node type (node_doctype) and a special parse flag,
parse_doctype, to add such nodes to the document during parsing
</li>
<li class="listitem">
Added parse_full parse flag mask, which extends parse_default with
all node type parsing flags except parse_ws_pcdata
</li>
<li class="listitem">
Added xml_node::hash_value() and xml_attribute::hash_value() functions
for use in hash-based containers
</li>
<li class="listitem">
Added internal_object() and additional constructor for both xml_node
and xml_attribute for easier marshalling (useful for language bindings)
</li>
<li class="listitem">
Added xml_document::document_element() function
</li>
<li class="listitem">
Added xml_node::prepend_attribute, xml_node::prepend_child and xml_node::prepend_copy
functions
</li>
<li class="listitem">
Added xml_node::append_child, xml_node::prepend_child, xml_node::insert_child_before
and xml_node::insert_child_after overloads for element nodes (with
name instead of type)
</li>
<li class="listitem">
Added xml_document::reset() function
</li>
</ol></div>
</li>
<li class="listitem">
Performance improvements:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
xml_node::root() and xml_node::offset_debug() are now O(1) instead
of O(logN)
</li>
<li class="listitem">
Minor parsing optimizations
</li>
<li class="listitem">
Minor memory optimization for strings in DOM tree (set_name/set_value)
</li>
<li class="listitem">
Memory optimization for string memory reclaiming in DOM tree (set_name/set_value
now reallocate the buffer if memory waste is too big)
</li>
<li class="listitem">
XPath: optimized document order sorting
</li>
<li class="listitem">
XPath: optimized child/attribute axis step
</li>
<li class="listitem">
XPath: optimized number-to-string conversions in MSVC
</li>
<li class="listitem">
XPath: optimized concat for many arguments
</li>
<li class="listitem">
XPath: optimized evaluation allocation mechanism: constant and document
strings are not heap-allocated
</li>
<li class="listitem">
XPath: optimized evaluation allocation mechanism: all temporaries'
allocations use fast stack-like allocator
</li>
</ol></div>
</li>
<li class="listitem">
Compatibility:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Removed wildcard functions (xml_node::child_w, xml_node::attribute_w,
etc.)
</li>
<li class="listitem">
Removed xml_node::all_elements_by_name
</li>
<li class="listitem">
Removed xpath_type_t enumeration; use xpath_value_type instead
</li>
<li class="listitem">
Removed format_write_bom_utf8 enumeration; use format_write_bom instead
</li>
<li class="listitem">
Removed xml_document::precompute_document_order, xml_attribute::document_order
and xml_node::document_order functions; document order sort optimization
is now automatic
</li>
<li class="listitem">
Removed xml_document::parse functions and transfer_ownership struct;
use xml_document::load_buffer_inplace and xml_document::load_buffer_inplace_own
instead
</li>
<li class="listitem">
Removed as_utf16 function; use as_wide instead
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.1_07_2010___version_0_9"></a><h6>
<a class="link" href="changes.html#manual.changes.1_07_2010___version_0_9">1.07.2010 - version
0.9</a>
</h6>
<p>
Major release, featuring extended and improved Unicode support, miscellaneous
performance improvements, bug fixes and more.
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Major Unicode improvements:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Introduced encoding support (automatic/manual encoding detection
on load, manual encoding selection on save, conversion from/to UTF8,
UTF16 LE/BE, UTF32 LE/BE)
</li>
<li class="listitem">
Introduced wchar_t mode (you can set PUGIXML_WCHAR_MODE define to
switch pugixml internal encoding from UTF8 to wchar_t; all functions
are switched to their Unicode variants)
</li>
<li class="listitem">
Load/save functions now support wide streams
</li>
</ol></div>
</li>
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed document corruption on failed parsing bug
</li>
<li class="listitem">
XPath string &lt;-&gt; number conversion improvements (increased
precision, fixed crash for huge numbers)
</li>
<li class="listitem">
Improved DOCTYPE parsing: now parser recognizes all well-formed DOCTYPE
declarations
</li>
<li class="listitem">
Fixed xml_attribute::as_uint() for large numbers (i.e. 2^32-1)
</li>
<li class="listitem">
Fixed xml_node::first_element_by_path for path components that are
prefixes of node names, but are not exactly equal to them.
</li>
</ol></div>
</li>
<li class="listitem">
Specification changes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
parse() API changed to load_buffer/load_buffer_inplace/load_buffer_inplace_own;
load_buffer APIs do not require zero-terminated strings.
</li>
<li class="listitem">
Renamed as_utf16 to as_wide
</li>
<li class="listitem">
Changed xml_node::offset_debug return type and xml_parse_result::offset
type to ptrdiff_t
</li>
<li class="listitem">
Nodes/attributes with empty names are now printed as :anonymous
</li>
</ol></div>
</li>
<li class="listitem">
Performance improvements:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Optimized document parsing and saving
</li>
<li class="listitem">
Changed internal memory management: internal allocator is used for
both metadata and name/value data; allocated pages are deleted if
all allocations from them are deleted
</li>
<li class="listitem">
Optimized memory consumption: sizeof(xml_node_struct) reduced from
40 bytes to 32 bytes on x86
</li>
<li class="listitem">
Optimized debug mode parsing/saving by order of magnitude
</li>
</ol></div>
</li>
<li class="listitem">
Miscellaneous:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
All STL includes except &lt;exception&gt; in pugixml.hpp are replaced
with forward declarations
</li>
<li class="listitem">
xml_node::remove_child and xml_node::remove_attribute now return
the operation result
</li>
</ol></div>
</li>
<li class="listitem">
Compatibility:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
parse() and as_utf16 are left for compatibility (these functions
are deprecated and will be removed in version 1.0)
</li>
<li class="listitem">
Wildcard functions, document_order/precompute_document_order functions,
all_elements_by_name function and format_write_bom_utf8 flag are
deprecated and will be removed in version 1.0
</li>
<li class="listitem">
xpath_type_t enumeration was renamed to xpath_value_type; xpath_type_t
is deprecated and will be removed in version 1.0
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.8_11_2009___version_0_5"></a><h6>
<a class="link" href="changes.html#manual.changes.8_11_2009___version_0_5">8.11.2009 - version
0.5</a>
</h6>
<p>
Major bugfix release. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
XPath bugfixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed translate(), lang() and concat() functions (infinite loops/crashes)
</li>
<li class="listitem">
Fixed compilation of queries with empty literal strings ("")
</li>
<li class="listitem">
Fixed axis tests: they never add empty nodes/attributes to the resulting
node set now
</li>
<li class="listitem">
Fixed string-value evaluation for node-set (the result excluded some
text descendants)
</li>
<li class="listitem">
Fixed self:: axis (it behaved like ancestor-or-self::)
</li>
<li class="listitem">
Fixed following:: and preceding:: axes (they included descendent
and ancestor nodes, respectively)
</li>
<li class="listitem">
Minor fix for namespace-uri() function (namespace declaration scope
includes the parent element of namespace declaration attribute)
</li>
<li class="listitem">
Some incorrect queries are no longer parsed now (i.e. foo: *)
</li>
<li class="listitem">
Fixed text()/etc. node test parsing bug (i.e. foo[text()] failed
to compile)
</li>
<li class="listitem">
Fixed root step (/) - it now selects empty node set if query is evaluated
on empty node
</li>
<li class="listitem">
Fixed string to number conversion ("123 " converted to
NaN, "123 .456" converted to 123.456 - now the results
are 123 and NaN, respectively)
</li>
<li class="listitem">
Node set copying now preserves sorted type; leads to better performance
on some queries
</li>
</ol></div>
</li>
<li class="listitem">
Miscellaneous bugfixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed xml_node::offset_debug for PI nodes
</li>
<li class="listitem">
Added empty attribute checks to xml_node::remove_attribute
</li>
<li class="listitem">
Fixed node_pi and node_declaration copying
</li>
<li class="listitem">
Const-correctness fixes
</li>
</ol></div>
</li>
<li class="listitem">
Specification changes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
xpath_node::select_nodes() and related functions now throw exception
if expression return type is not node set (instead of assertion)
</li>
<li class="listitem">
xml_node::traverse() now sets depth to -1 for both begin() and end()
callbacks (was 0 at begin() and -1 at end())
</li>
<li class="listitem">
In case of non-raw node printing a newline is output after PCDATA
inside nodes if the PCDATA has siblings
</li>
<li class="listitem">
UTF8 -&gt; wchar_t conversion now considers 5-byte UTF8-like sequences
as invalid
</li>
</ol></div>
</li>
<li class="listitem">
New features:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Added xpath_node_set::operator[] for index-based iteration
</li>
<li class="listitem">
Added xpath_query::return_type()
</li>
<li class="listitem">
Added getter accessors for memory-management functions
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.17_09_2009___version_0_42"></a><h6>
<a class="link" href="changes.html#manual.changes.17_09_2009___version_0_42">17.09.2009 - version
0.42</a>
</h6>
<p>
Maintenance release. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed deallocation in case of custom allocation functions or if delete[]
/ free are incompatible
</li>
<li class="listitem">
XPath parser fixed for incorrect queries (i.e. incorrect XPath queries
should now always fail to compile)
</li>
<li class="listitem">
Const-correctness fixes for find_child_by_attribute
</li>
<li class="listitem">
Improved compatibility (miscellaneous warning fixes, fixed cstring
include dependency for GCC)
</li>
<li class="listitem">
Fixed iterator begin/end and print function to work correctly for
empty nodes
</li>
</ol></div>
</li>
<li class="listitem">
New features:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Added PUGIXML_API/PUGIXML_CLASS/PUGIXML_FUNCTION configuration macros
to control class/function attributes
</li>
<li class="listitem">
Added xml_attribute::set_value overloads for different types
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.8_02_2009___version_0_41"></a><h6>
<a class="link" href="changes.html#manual.changes.8_02_2009___version_0_41">8.02.2009 - version
0.41</a>
</h6>
<p>
Maintenance release. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
Fixed bug with node printing (occasionally some content was not written
to output stream)
</li></ol></div>
</li></ul></div>
<a name="manual.changes.18_01_2009___version_0_4"></a><h6>
<a class="link" href="changes.html#manual.changes.18_01_2009___version_0_4">18.01.2009 - version
0.4</a>
</h6>
<p>
Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Documentation fix in samples for parse() with manual lifetime control
</li>
<li class="listitem">
Fixed document order sorting in XPath (it caused wrong order of nodes
after xpath_node_set::sort and wrong results of some XPath queries)
</li>
</ol></div>
</li>
<li class="listitem">
Node printing changes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Single quotes are no longer escaped when printing nodes
</li>
<li class="listitem">
Symbols in second half of ASCII table are no longer escaped when
printing nodes; because of this, format_utf8 flag is deleted as it's
no longer needed and format_write_bom is renamed to format_write_bom_utf8.
</li>
<li class="listitem">
Reworked node printing - now it works via xml_writer interface; implementations
for FILE* and std::ostream are available. As a side-effect, xml_document::save_file
now works without STL.
</li>
</ol></div>
</li>
<li class="listitem">
New features:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Added unsigned integer support for attributes (xml_attribute::as_uint,
xml_attribute::operator=)
</li>
<li class="listitem">
Now document declaration (&lt;?xml ...?&gt;) is parsed as node with
type node_declaration when parse_declaration flag is specified (access
to encoding/version is performed as if they were attributes, i.e.
doc.child("xml").attribute("version").as_float());
corresponding flags for node printing were also added
</li>
<li class="listitem">
Added support for custom memory management (see set_memory_management_functions
for details)
</li>
<li class="listitem">
Implemented node/attribute copying (see xml_node::insert_copy_* and
xml_node::append_copy for details)
</li>
<li class="listitem">
Added find_child_by_attribute and find_child_by_attribute_w to simplify
parsing code in some cases (i.e. COLLADA files)
</li>
<li class="listitem">
Added file offset information querying for debugging purposes (now
you're able to determine exact location of any xml_node in parsed
file, see xml_node::offset_debug for details)
</li>
<li class="listitem">
Improved error handling for parsing - now load(), load_file() and
parse() return xml_parse_result, which contains error code and last
parsed offset; this does not break old interface as xml_parse_result
can be implicitly casted to bool.
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.31_10_2007___version_0_34"></a><h6>
<a class="link" href="changes.html#manual.changes.31_10_2007___version_0_34">31.10.2007 - version
0.34</a>
</h6>
<p>
Maintenance release. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed bug with loading from text-mode iostreams
</li>
<li class="listitem">
Fixed leak when transfer_ownership is true and parsing is failing
</li>
<li class="listitem">
Fixed bug in saving (\r and \n are now escaped in attribute values)
</li>
<li class="listitem">
Renamed free() to destroy() - some macro conflicts were reported
</li>
</ol></div>
</li>
<li class="listitem">
New features:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Improved compatibility (supported Digital Mars C++, MSVC 6, CodeWarrior
8, PGI C++, Comeau, supported PS3 and XBox360)
</li>
<li class="listitem">
PUGIXML_NO_EXCEPTION flag for platforms without exception handling
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.21_02_2007___version_0_3"></a><h6>
<a class="link" href="changes.html#manual.changes.21_02_2007___version_0_3">21.02.2007 - version
0.3</a>
</h6>
<p>
Refactored, reworked and improved version. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Interface:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Added XPath
</li>
<li class="listitem">
Added tree modification functions
</li>
<li class="listitem">
Added no STL compilation mode
</li>
<li class="listitem">
Added saving document to file
</li>
<li class="listitem">
Refactored parsing flags
</li>
<li class="listitem">
Removed xml_parser class in favor of xml_document
</li>
<li class="listitem">
Added transfer ownership parsing mode
</li>
<li class="listitem">
Modified the way xml_tree_walker works
</li>
<li class="listitem">
Iterators are now non-constant
</li>
</ol></div>
</li>
<li class="listitem">
Implementation:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Support of several compilers and platforms
</li>
<li class="listitem">
Refactored and sped up parsing core
</li>
<li class="listitem">
Improved standard compliancy
</li>
<li class="listitem">
Added XPath implementation
</li>
<li class="listitem">
Fixed several bugs
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.6_11_2006___version_0_2"></a><h6>
<a class="link" href="changes.html#manual.changes.6_11_2006___version_0_2">6.11.2006 - version
0.2</a>
</h6>
<p>
First public release. Changes:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Bug fixes:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Fixed child_value() (for empty nodes)
</li>
<li class="listitem">
Fixed xml_parser_impl warning at W4
</li>
</ol></div>
</li>
<li class="listitem">
New features:
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Introduced child_value(name) and child_value_w(name)
</li>
<li class="listitem">
parse_eol_pcdata and parse_eol_attribute flags + parse_minimal optimizations
</li>
<li class="listitem">
Optimizations of strconv_t
</li>
</ol></div>
</li>
</ul></div>
<a name="manual.changes.15_07_2006___version_0_1"></a><h6>
<a class="link" href="changes.html#manual.changes.15_07_2006___version_0_1">15.07.2006 - version
0.1</a>
</h6>
<p>
First private release for testing purposes
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="xpath.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="apiref.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
+682
View File
@@ -0,0 +1,682 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Document object model</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="install.html" title="Installation">
<link rel="next" href="loading.html" title="Loading document">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<b>Object model</b> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="install.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="loading.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.dom"></a><a class="link" href="dom.html" title="Document object model"> Document object model</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="dom.html#manual.dom.tree"> Tree structure</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.cpp"> C++ interface</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.unicode"> Unicode interface</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.thread"> Thread-safety guarantees</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.exception"> Exception guarantees</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.memory"> Memory management</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="dom.html#manual.dom.memory.custom"> Custom memory allocation/deallocation
functions</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.memory.internals"> Document memory management
internals</a></span></dt>
</dl></dd>
</dl></div>
<p>
pugixml stores XML data in DOM-like way: the entire XML document (both document
structure and element data) is stored in memory as a tree. The tree can be
loaded from a character stream (file, string, C++ I/O stream), then traversed
with the special API or XPath expressions. The whole tree is mutable: both
node structure and node/attribute data can be changed at any time. Finally,
the result of document transformations can be saved to a character stream (file,
C++ I/O stream or custom transport).
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.tree"></a><a class="link" href="dom.html#manual.dom.tree" title="Tree structure"> Tree structure</a>
</h3></div></div></div>
<p>
The XML document is represented with a tree data structure. The root of the
tree is the document itself, which corresponds to C++ type <a class="link" href="dom.html#xml_document">xml_document</a>.
Document has one or more child nodes, which correspond to C++ type <a class="link" href="dom.html#xml_node">xml_node</a>. Nodes have different types; depending
on a type, a node can have a collection of child nodes, a collection of attributes,
which correspond to C++ type <a class="link" href="dom.html#xml_attribute">xml_attribute</a>,
and some additional data (i.e. name).
</p>
<a name="xml_node_type"></a><p>
The tree nodes can be of one of the following types (which together form
the enumeration <code class="computeroutput"><span class="identifier">xml_node_type</span></code>):
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Document node (<a name="node_document"></a><code class="literal">node_document</code>) - this
is the root of the tree, which consists of several child nodes. This
node corresponds to <a class="link" href="dom.html#xml_document">xml_document</a>
class; note that <a class="link" href="dom.html#xml_document">xml_document</a> is
a sub-class of <a class="link" href="dom.html#xml_node">xml_node</a>, so the entire
node interface is also available. However, document node is special in
several ways, which are covered below. There can be only one document
node in the tree; document node does not have any XML representation.
<br><br>
</li>
<li class="listitem">
Element/tag node (<a name="node_element"></a><code class="literal">node_element</code>) - this
is the most common type of node, which represents XML elements. Element
nodes have a name, a collection of attributes and a collection of child
nodes (both of which may be empty). The attribute is a simple name/value
pair. The example XML representation of element nodes is as follows:
</li>
</ul></div>
<pre class="programlisting"><span class="special">&lt;</span><span class="identifier">node</span> <span class="identifier">attr</span><span class="special">=</span><span class="string">"value"</span><span class="special">&gt;&lt;</span><span class="identifier">child</span><span class="special">/&gt;&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
There are two element nodes here: one has name <code class="computeroutput"><span class="string">"node"</span></code>,
single attribute <code class="computeroutput"><span class="string">"attr"</span></code>
and single child <code class="computeroutput"><span class="string">"child"</span></code>,
another has name <code class="computeroutput"><span class="string">"child"</span></code>
and does not have any attributes or child nodes.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Plain character data nodes (<a name="node_pcdata"></a><code class="literal">node_pcdata</code>)
represent plain text in XML. PCDATA nodes have a value, but do not have
a name or children/attributes. Note that plain character data is not
a part of the element node but instead has its own node; for example,
an element node can have several child PCDATA nodes. The example XML
representation of text nodes is as follows:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span> <span class="identifier">text1</span> <span class="special">&lt;</span><span class="identifier">child</span><span class="special">/&gt;</span> <span class="identifier">text2</span> <span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
Here <code class="computeroutput"><span class="string">"node"</span></code> element
has three children, two of which are PCDATA nodes with values <code class="computeroutput"><span class="string">"text1"</span></code> and <code class="computeroutput"><span class="string">"text2"</span></code>.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Character data nodes (<a name="node_cdata"></a><code class="literal">node_cdata</code>) represent
text in XML that is quoted in a special way. CDATA nodes do not differ
from PCDATA nodes except in XML representation - the above text example
looks like this with CDATA:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span> <span class="special">&lt;![</span><span class="identifier">CDATA</span><span class="special">[[</span><span class="identifier">text1</span><span class="special">]]&gt;</span> <span class="special">&lt;</span><span class="identifier">child</span><span class="special">/&gt;</span> <span class="special">&lt;![</span><span class="identifier">CDATA</span><span class="special">[[</span><span class="identifier">text2</span><span class="special">]]&gt;</span> <span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
CDATA nodes make it easy to include non-escaped &lt;, &amp; and &gt; characters
in plain text. CDATA value can not contain the character sequence ]]&gt;,
since it is used to determine the end of node contents.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Comment nodes (<a name="node_comment"></a><code class="literal">node_comment</code>) represent
comments in XML. Comment nodes have a value, but do not have a name or
children/attributes. The example XML representation of a comment node
is as follows:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;!--</span> <span class="identifier">comment</span> <span class="identifier">text</span> <span class="special">--&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
Here the comment node has value <code class="computeroutput"><span class="string">"comment
text"</span></code>. By default comment nodes are treated as non-essential
part of XML markup and are not loaded during XML parsing. You can override
this behavior with <a class="link" href="loading.html#parse_comments">parse_comments</a>
flag.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Processing instruction node (<a name="node_pi"></a><code class="literal">node_pi</code>) represent
processing instructions (PI) in XML. PI nodes have a name and an optional
value, but do not have children/attributes. The example XML representation
of a PI node is as follows:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;?</span><span class="identifier">name</span> <span class="identifier">value</span><span class="special">?&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
Here the name (also called PI target) is <code class="computeroutput"><span class="string">"name"</span></code>,
and the value is <code class="computeroutput"><span class="string">"value"</span></code>.
By default PI nodes are treated as non-essential part of XML markup and
are not loaded during XML parsing. You can override this behavior with
<a class="link" href="loading.html#parse_pi">parse_pi</a> flag.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Declaration node (<a name="node_declaration"></a><code class="literal">node_declaration</code>)
represents document declarations in XML. Declaration nodes have a name
(<code class="computeroutput"><span class="string">"xml"</span></code>) and an
optional collection of attributes, but do not have value or children.
There can be only one declaration node in a document; moreover, it should
be the topmost node (its parent should be the document). The example
XML representation of a declaration node is as follows:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;?</span><span class="identifier">xml</span> <span class="identifier">version</span><span class="special">=</span><span class="string">"1.0"</span><span class="special">?&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
Here the node has name <code class="computeroutput"><span class="string">"xml"</span></code>
and a single attribute with name <code class="computeroutput"><span class="string">"version"</span></code>
and value <code class="computeroutput"><span class="string">"1.0"</span></code>.
By default declaration nodes are treated as non-essential part of XML markup
and are not loaded during XML parsing. You can override this behavior with
<a class="link" href="loading.html#parse_declaration">parse_declaration</a> flag. Also,
by default a dummy declaration is output when XML document is saved unless
there is already a declaration in the document; you can disable this with
<a class="link" href="saving.html#format_no_declaration">format_no_declaration</a> flag.
</p></blockquote></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
Document type declaration node (<a name="node_doctype"></a><code class="literal">node_doctype</code>)
represents document type declarations in XML. Document type declaration
nodes have a value, which corresponds to the entire document type contents;
no additional nodes are created for inner elements like <code class="computeroutput"><span class="special">&lt;!</span><span class="identifier">ENTITY</span><span class="special">&gt;</span></code>. There can be only one document type
declaration node in a document; moreover, it should be the topmost node
(its parent should be the document). The example XML representation of
a document type declaration node is as follows:
</li></ul></div>
<pre class="programlisting"><span class="special">&lt;!</span><span class="identifier">DOCTYPE</span> <span class="identifier">greeting</span> <span class="special">[</span> <span class="special">&lt;!</span><span class="identifier">ELEMENT</span> <span class="identifier">greeting</span> <span class="special">(</span><span class="preprocessor">#PCDATA</span><span class="special">)&gt;</span> <span class="special">]&gt;</span>
</pre>
<div class="blockquote"><blockquote class="blockquote"><p>
Here the node has value <code class="computeroutput"><span class="string">"greeting [ &lt;!ELEMENT
greeting (#PCDATA)&gt; ]"</span></code>. By default document type
declaration nodes are treated as non-essential part of XML markup and are
not loaded during XML parsing. You can override this behavior with <a class="link" href="loading.html#parse_doctype">parse_doctype</a> flag.
</p></blockquote></div>
<p>
Finally, here is a complete example of XML document and the corresponding
tree representation (<a href="../samples/tree.xml" target="_top">samples/tree.xml</a>):
</p>
<div class="informaltable"><table class="table">
<colgroup>
<col>
<col>
</colgroup>
<tbody><tr>
<td>
<p>
</p>
<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"><span class="special">&lt;?</span><span class="identifier">xml</span> <span class="identifier">version</span><span class="special">=</span><span class="string">"1.0"</span><span class="special">?&gt;</span>
<span class="special">&lt;</span><span class="identifier">mesh</span> <span class="identifier">name</span><span class="special">=</span><span class="string">"mesh_root"</span><span class="special">&gt;</span>
<span class="special">&lt;!--</span> <span class="identifier">here</span> <span class="identifier">is</span> <span class="identifier">a</span> <span class="identifier">mesh</span> <span class="identifier">node</span> <span class="special">--&gt;</span>
<span class="identifier">some</span> <span class="identifier">text</span>
<span class="special">&lt;![</span><span class="identifier">CDATA</span><span class="special">[</span><span class="identifier">someothertext</span><span class="special">]]&gt;</span>
<span class="identifier">some</span> <span class="identifier">more</span> <span class="identifier">text</span>
<span class="special">&lt;</span><span class="identifier">node</span> <span class="identifier">attr1</span><span class="special">=</span><span class="string">"value1"</span> <span class="identifier">attr2</span><span class="special">=</span><span class="string">"value2"</span> <span class="special">/&gt;</span>
<span class="special">&lt;</span><span class="identifier">node</span> <span class="identifier">attr1</span><span class="special">=</span><span class="string">"value2"</span><span class="special">&gt;</span>
<span class="special">&lt;</span><span class="identifier">innernode</span><span class="special">/&gt;</span>
<span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span>
<span class="special">&lt;/</span><span class="identifier">mesh</span><span class="special">&gt;</span>
<span class="special">&lt;?</span><span class="identifier">include</span> <span class="identifier">somedata</span><span class="special">?&gt;</span>
</pre>
<p>
</p>
</td>
<td>
<p>
<a href="../images/dom_tree.png" target="_top"><span class="inlinemediaobject"><img src="../images/dom_tree_thumb.png" alt="dom_tree_thumb"></span></a>
</p>
</td>
</tr></tbody>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.cpp"></a><a class="link" href="dom.html#manual.dom.cpp" title="C++ interface"> C++ interface</a>
</h3></div></div></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
All pugixml classes and functions are located in the <code class="computeroutput"><span class="identifier">pugi</span></code>
namespace; you have to either use explicit name qualification (i.e. <code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span></code>), or to gain access to relevant
symbols via <code class="computeroutput"><span class="keyword">using</span></code> directive
(i.e. <code class="computeroutput"><span class="keyword">using</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">;</span></code> or <code class="computeroutput"><span class="keyword">using</span>
<span class="keyword">namespace</span> <span class="identifier">pugi</span><span class="special">;</span></code>). The namespace will be omitted from all
declarations in this documentation hereafter; all code examples will use
fully qualified names.
</p></td></tr>
</table></div>
<p>
Despite the fact that there are several node types, there are only three
C++ classes representing the tree (<code class="computeroutput"><span class="identifier">xml_document</span></code>,
<code class="computeroutput"><span class="identifier">xml_node</span></code>, <code class="computeroutput"><span class="identifier">xml_attribute</span></code>);
some operations on <code class="computeroutput"><span class="identifier">xml_node</span></code>
are only valid for certain node types. The classes are described below.
</p>
<a name="xml_document"></a><a name="xml_document::document_element"></a><p>
<code class="computeroutput"><span class="identifier">xml_document</span></code> is the owner
of the entire document structure; it is a non-copyable class. The interface
of <code class="computeroutput"><span class="identifier">xml_document</span></code> consists
of loading functions (see <a class="xref" href="loading.html" title="Loading document"> Loading document</a>), saving functions (see <a class="xref" href="saving.html" title="Saving document"> Saving document</a>)
and the entire interface of <code class="computeroutput"><span class="identifier">xml_node</span></code>,
which allows for document inspection and/or modification. Note that while
<code class="computeroutput"><span class="identifier">xml_document</span></code> is a sub-class
of <code class="computeroutput"><span class="identifier">xml_node</span></code>, <code class="computeroutput"><span class="identifier">xml_node</span></code> is not a polymorphic type; the
inheritance is present only to simplify usage. Alternatively you can use
the <code class="computeroutput"><span class="identifier">document_element</span></code> function
to get the element node that's the immediate child of the document.
</p>
<a name="xml_document::ctor"></a><a name="xml_document::dtor"></a><a name="xml_document::reset"></a><p>
Default constructor of <code class="computeroutput"><span class="identifier">xml_document</span></code>
initializes the document to the tree with only a root node (document node).
You can then populate it with data using either tree modification functions
or loading functions; all loading functions destroy the previous tree with
all occupied memory, which puts existing node/attribute handles for this
document to invalid state. If you want to destroy the previous tree, you
can use the <code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">reset</span></code>
function; it destroys the tree and replaces it with either an empty one or
a copy of the specified document. Destructor of <code class="computeroutput"><span class="identifier">xml_document</span></code>
also destroys the tree, thus the lifetime of the document object should exceed
the lifetimes of any node/attribute handles that point to the tree.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
While technically node/attribute handles can be alive when the tree they're
referring to is destroyed, calling any member function for these handles
results in undefined behavior. Thus it is recommended to make sure that
the document is destroyed only after all references to its nodes/attributes
are destroyed.
</p></td></tr>
</table></div>
<a name="xml_node"></a><a name="xml_node::type"></a><p>
<code class="computeroutput"><span class="identifier">xml_node</span></code> is the handle to
document node; it can point to any node in the document, including the document
node itself. There is a common interface for nodes of all types; the actual
<a class="link" href="dom.html#xml_node_type">node type</a> can be queried via the <code class="computeroutput"><span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">type</span><span class="special">()</span></code>
method. Note that <code class="computeroutput"><span class="identifier">xml_node</span></code>
is only a handle to the actual node, not the node itself - you can have several
<code class="computeroutput"><span class="identifier">xml_node</span></code> handles pointing
to the same underlying object. Destroying <code class="computeroutput"><span class="identifier">xml_node</span></code>
handle does not destroy the node and does not remove it from the tree. The
size of <code class="computeroutput"><span class="identifier">xml_node</span></code> is equal
to that of a pointer, so it is nothing more than a lightweight wrapper around
a pointer; you can safely pass or return <code class="computeroutput"><span class="identifier">xml_node</span></code>
objects by value without additional overhead.
</p>
<a name="node_null"></a><p>
There is a special value of <code class="computeroutput"><span class="identifier">xml_node</span></code>
type, known as null node or empty node (such nodes have type <code class="computeroutput"><span class="identifier">node_null</span></code>). It does not correspond to any
node in any document, and thus resembles null pointer. However, all operations
are defined on empty nodes; generally the operations don't do anything and
return empty nodes/attributes or empty strings as their result (see documentation
for specific functions for more detailed information). This is useful for
chaining calls; i.e. you can get the grandparent of a node like so: <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">parent</span><span class="special">().</span><span class="identifier">parent</span><span class="special">()</span></code>; if a node is a null node or it does not
have a parent, the first <code class="computeroutput"><span class="identifier">parent</span><span class="special">()</span></code> call returns null node; the second <code class="computeroutput"><span class="identifier">parent</span><span class="special">()</span></code>
call then also returns null node, which makes error handling easier.
</p>
<a name="xml_attribute"></a><p>
<code class="computeroutput"><span class="identifier">xml_attribute</span></code> is the handle
to an XML attribute; it has the same semantics as <code class="computeroutput"><span class="identifier">xml_node</span></code>,
i.e. there can be several <code class="computeroutput"><span class="identifier">xml_attribute</span></code>
handles pointing to the same underlying object and there is a special null
attribute value, which propagates to function results.
</p>
<a name="xml_attribute::ctor"></a><a name="xml_node::ctor"></a><p>
Both <code class="computeroutput"><span class="identifier">xml_node</span></code> and <code class="computeroutput"><span class="identifier">xml_attribute</span></code> have the default constructor
which initializes them to null objects.
</p>
<a name="xml_attribute::comparison"></a><a name="xml_node::comparison"></a><p>
<code class="computeroutput"><span class="identifier">xml_node</span></code> and <code class="computeroutput"><span class="identifier">xml_attribute</span></code> try to behave like pointers,
that is, they can be compared with other objects of the same type, making
it possible to use them as keys in associative containers. All handles to
the same underlying object are equal, and any two handles to different underlying
objects are not equal. Null handles only compare as equal to themselves.
The result of relational comparison can not be reliably determined from the
order of nodes in file or in any other way. Do not use relational comparison
operators except for search optimization (i.e. associative container keys).
</p>
<a name="xml_attribute::hash_value"></a><a name="xml_node::hash_value"></a><p>
If you want to use <code class="computeroutput"><span class="identifier">xml_node</span></code>
or <code class="computeroutput"><span class="identifier">xml_attribute</span></code> objects
as keys in hash-based associative containers, you can use the <code class="computeroutput"><span class="identifier">hash_value</span></code> member functions. They return
the hash values that are guaranteed to be the same for all handles to the
same underlying object. The hash value for null handles is 0.
</p>
<a name="xml_attribute::unspecified_bool_type"></a><a name="xml_node::unspecified_bool_type"></a><a name="xml_attribute::empty"></a><a name="xml_node::empty"></a><p>
Finally handles can be implicitly cast to boolean-like objects, so that you
can test if the node/attribute is empty with the following code: <code class="computeroutput"><span class="keyword">if</span> <span class="special">(</span><span class="identifier">node</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span>
<span class="special">}</span></code> or <code class="computeroutput"><span class="keyword">if</span>
<span class="special">(!</span><span class="identifier">node</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>.
Alternatively you can check if a given <code class="computeroutput"><span class="identifier">xml_node</span></code>/<code class="computeroutput"><span class="identifier">xml_attribute</span></code> handle is null by calling
the following methods:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">empty</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">empty</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
Nodes and attributes do not exist without a document tree, so you can't create
them without adding them to some document. Once underlying node/attribute
objects are destroyed, the handles to those objects become invalid. While
this means that destruction of the entire tree invalidates all node/attribute
handles, it also means that destroying a subtree (by calling <a class="link" href="modify.html#xml_node::remove_child">xml_node::remove_child</a>)
or removing an attribute invalidates the corresponding handles. There is
no way to check handle validity; you have to ensure correctness through external
mechanisms.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.unicode"></a><a class="link" href="dom.html#manual.dom.unicode" title="Unicode interface"> Unicode interface</a>
</h3></div></div></div>
<p>
There are two choices of interface and internal representation when configuring
pugixml: you can either choose the UTF-8 (also called char) interface or
UTF-16/32 (also called wchar_t) one. The choice is controlled via <a class="link" href="install.html#PUGIXML_WCHAR_MODE">PUGIXML_WCHAR_MODE</a>
define; you can set it via <code class="filename">pugiconfig.hpp</code> or via preprocessor options, as
discussed in <a class="xref" href="install.html#manual.install.building.config" title="Additional configuration options"> Additional configuration
options</a>. If this define is set, the wchar_t
interface is used; otherwise (by default) the char interface is used. The
exact wide character encoding is assumed to be either UTF-16 or UTF-32 and
is determined based on the size of <code class="computeroutput"><span class="keyword">wchar_t</span></code>
type.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
If the size of <code class="computeroutput"><span class="keyword">wchar_t</span></code> is
2, pugixml assumes UTF-16 encoding instead of UCS-2, which means that some
characters are represented as two code points.
</p></td></tr>
</table></div>
<p>
All tree functions that work with strings work with either C-style null terminated
strings or STL strings of the selected character type. For example, node
name accessors look like this in char mode:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">name</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">set_name</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">value</span><span class="special">);</span>
</pre>
<p>
and like this in wchar_t mode:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">name</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">set_name</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> <span class="identifier">value</span><span class="special">);</span>
</pre>
<a name="char_t"></a><a name="string_t"></a><p>
There is a special type, <code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">char_t</span></code>,
that is defined as the character type and depends on the library configuration;
it will be also used in the documentation hereafter. There is also a type
<code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">string_t</span></code>, which is defined as the STL string
of the character type; it corresponds to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
in char mode and to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wstring</span></code> in wchar_t mode.
</p>
<p>
In addition to the interface, the internal implementation changes to store
XML data as <code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">char_t</span></code>; this means that these two modes
have different memory usage characteristics. The conversion to <code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">char_t</span></code> upon document loading and from
<code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">char_t</span></code> upon document saving happen automatically,
which also carries minor performance penalty. The general advice however
is to select the character mode based on usage scenario, i.e. if UTF-8 is
inconvenient to process and most of your XML data is non-ASCII, wchar_t mode
is probably a better choice.
</p>
<a name="as_utf8"></a><a name="as_wide"></a><p>
There are cases when you'll have to convert string data between UTF-8 and
wchar_t encodings; the following helper functions are provided for such purposes:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">as_utf8</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> <span class="identifier">str</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">wstring</span> <span class="identifier">as_wide</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">str</span><span class="special">);</span>
</pre>
<p>
Both functions accept a null-terminated string as an argument <code class="computeroutput"><span class="identifier">str</span></code>, and return the converted string.
<code class="computeroutput"><span class="identifier">as_utf8</span></code> performs conversion
from UTF-16/32 to UTF-8; <code class="computeroutput"><span class="identifier">as_wide</span></code>
performs conversion from UTF-8 to UTF-16/32. Invalid UTF sequences are silently
discarded upon conversion. <code class="computeroutput"><span class="identifier">str</span></code>
has to be a valid string; passing null pointer results in undefined behavior.
There are also two overloads with the same semantics which accept a string
as an argument:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">as_utf8</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">wstring</span><span class="special">&amp;</span> <span class="identifier">str</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">wstring</span> <span class="identifier">as_wide</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">str</span><span class="special">);</span>
</pre>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top">
<p>
Most examples in this documentation assume char interface and therefore
will not compile with <a class="link" href="install.html#PUGIXML_WCHAR_MODE">PUGIXML_WCHAR_MODE</a>.
This is done to simplify the documentation; usually the only changes you'll
have to make is to pass <code class="computeroutput"><span class="keyword">wchar_t</span></code>
string literals, i.e. instead of
</p>
<p>
<code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span>
<span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"bookstore"</span><span class="special">).</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="string">"book"</span><span class="special">,</span> <span class="string">"id"</span><span class="special">,</span> <span class="string">"12345"</span><span class="special">);</span></code>
</p>
<p>
you'll have to do
</p>
<p>
<code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span>
<span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="identifier">L</span><span class="string">"bookstore"</span><span class="special">).</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="identifier">L</span><span class="string">"book"</span><span class="special">,</span> <span class="identifier">L</span><span class="string">"id"</span><span class="special">,</span> <span class="identifier">L</span><span class="string">"12345"</span><span class="special">);</span></code>
</p>
</td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.thread"></a><a class="link" href="dom.html#manual.dom.thread" title="Thread-safety guarantees"> Thread-safety guarantees</a>
</h3></div></div></div>
<p>
Almost all functions in pugixml have the following thread-safety guarantees:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
it is safe to call free (non-member) functions from multiple threads
</li>
<li class="listitem">
it is safe to perform concurrent read-only accesses to the same tree
(all constant member functions do not modify the tree)
</li>
<li class="listitem">
it is safe to perform concurrent read/write accesses, if there is only
one read or write access to the single tree at a time
</li>
</ul></div>
<p>
Concurrent modification and traversing of a single tree requires synchronization,
for example via reader-writer lock. Modification includes altering document
structure and altering individual node/attribute data, i.e. changing names/values.
</p>
<p>
The only exception is <a class="link" href="dom.html#set_memory_management_functions">set_memory_management_functions</a>;
it modifies global variables and as such is not thread-safe. Its usage policy
has more restrictions, see <a class="xref" href="dom.html#manual.dom.memory.custom" title="Custom memory allocation/deallocation functions"> Custom memory allocation/deallocation
functions</a>.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.exception"></a><a class="link" href="dom.html#manual.dom.exception" title="Exception guarantees"> Exception guarantees</a>
</h3></div></div></div>
<p>
With the exception of XPath, pugixml itself does not throw any exceptions.
Additionally, most pugixml functions have a no-throw exception guarantee.
</p>
<p>
This is not applicable to functions that operate on STL strings or IOstreams;
such functions have either strong guarantee (functions that operate on strings)
or basic guarantee (functions that operate on streams). Also functions that
call user-defined callbacks (i.e. <a class="link" href="access.html#xml_node::traverse">xml_node::traverse</a>
or <a class="link" href="access.html#xml_node::find_node">xml_node::find_node</a>) do not
provide any exception guarantees beyond the ones provided by the callback.
</p>
<p>
If exception handling is not disabled with <a class="link" href="install.html#PUGIXML_NO_EXCEPTIONS">PUGIXML_NO_EXCEPTIONS</a>
define, XPath functions may throw <a class="link" href="xpath.html#xpath_exception">xpath_exception</a>
on parsing errors; also, XPath functions may throw <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bad_alloc</span></code>
in low memory conditions. Still, XPath functions provide strong exception
guarantee.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.dom.memory"></a><a class="link" href="dom.html#manual.dom.memory" title="Memory management"> Memory management</a>
</h3></div></div></div>
<p>
pugixml requests the memory needed for document storage in big chunks, and
allocates document data inside those chunks. This section discusses replacing
functions used for chunk allocation and internal memory management implementation.
</p>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.dom.memory.custom"></a><a class="link" href="dom.html#manual.dom.memory.custom" title="Custom memory allocation/deallocation functions"> Custom memory allocation/deallocation
functions</a>
</h4></div></div></div>
<a name="allocation_function"></a><a name="deallocation_function"></a><p>
All memory for tree structure, tree data and XPath objects is allocated
via globally specified functions, which default to malloc/free. You can
set your own allocation functions with set_memory_management function.
The function interfaces are the same as that of malloc/free:
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="keyword">void</span><span class="special">*</span> <span class="special">(*</span><span class="identifier">allocation_function</span><span class="special">)(</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">);</span>
<span class="keyword">typedef</span> <span class="keyword">void</span> <span class="special">(*</span><span class="identifier">deallocation_function</span><span class="special">)(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">ptr</span><span class="special">);</span>
</pre>
<a name="set_memory_management_functions"></a><a name="get_memory_allocation_function"></a><a name="get_memory_deallocation_function"></a><p>
You can use the following accessor functions to change or get current memory
management functions:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">set_memory_management_functions</span><span class="special">(</span><span class="identifier">allocation_function</span> <span class="identifier">allocate</span><span class="special">,</span> <span class="identifier">deallocation_function</span> <span class="identifier">deallocate</span><span class="special">);</span>
<span class="identifier">allocation_function</span> <span class="identifier">get_memory_allocation_function</span><span class="special">();</span>
<span class="identifier">deallocation_function</span> <span class="identifier">get_memory_deallocation_function</span><span class="special">();</span>
</pre>
<p>
Allocation function is called with the size (in bytes) as an argument and
should return a pointer to a memory block with alignment that is suitable
for storage of primitive types (usually a maximum of <code class="computeroutput"><span class="keyword">void</span><span class="special">*</span></code> and <code class="computeroutput"><span class="keyword">double</span></code>
types alignment is sufficient) and size that is greater than or equal to
the requested one. If the allocation fails, the function has to return
null pointer (throwing an exception from allocation function results in
undefined behavior).
</p>
<p>
Deallocation function is called with the pointer that was returned by some
call to allocation function; it is never called with a null pointer. If
memory management functions are not thread-safe, library thread safety
is not guaranteed.
</p>
<p>
This is a simple example of custom memory management (<a href="../samples/custom_memory_management.cpp" target="_top">samples/custom_memory_management.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">void</span><span class="special">*</span> <span class="identifier">custom_allocate</span><span class="special">(</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">new</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">nothrow</span><span class="special">)</span> <span class="keyword">char</span><span class="special">[</span><span class="identifier">size</span><span class="special">];</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">custom_deallocate</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">ptr</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">delete</span><span class="special">[]</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">*&gt;(</span><span class="identifier">ptr</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">set_memory_management_functions</span><span class="special">(</span><span class="identifier">custom_allocate</span><span class="special">,</span> <span class="identifier">custom_deallocate</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
When setting new memory management functions, care must be taken to make
sure that there are no live pugixml objects. Otherwise when the objects
are destroyed, the new deallocation function will be called with the memory
obtained by the old allocation function, resulting in undefined behavior.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.dom.memory.internals"></a><a class="link" href="dom.html#manual.dom.memory.internals" title="Document memory management internals"> Document memory management
internals</a>
</h4></div></div></div>
<p>
Constructing a document object using the default constructor does not result
in any allocations; document node is stored inside the <a class="link" href="dom.html#xml_document">xml_document</a>
object.
</p>
<p>
When the document is loaded from file/buffer, unless an inplace loading
function is used (see <a class="xref" href="loading.html#manual.loading.memory" title="Loading document from memory"> Loading document from memory</a>), a complete copy of character
stream is made; all names/values of nodes and attributes are allocated
in this buffer. This buffer is allocated via a single large allocation
and is only freed when document memory is reclaimed (i.e. if the <a class="link" href="dom.html#xml_document">xml_document</a> object is destroyed or if another
document is loaded in the same object). Also when loading from file or
stream, an additional large allocation may be performed if encoding conversion
is required; a temporary buffer is allocated, and it is freed before load
function returns.
</p>
<p>
All additional memory, such as memory for document structure (node/attribute
objects) and memory for node/attribute names/values is allocated in pages
on the order of 32 kilobytes; actual objects are allocated inside the pages
using a memory management scheme optimized for fast allocation/deallocation
of many small objects. Because of the scheme specifics, the pages are only
destroyed if all objects inside them are destroyed; also, generally destroying
an object does not mean that subsequent object creation will reuse the
same memory. This means that it is possible to devise a usage scheme which
will lead to higher memory usage than expected; one example is adding a
lot of nodes, and them removing all even numbered ones; not a single page
is reclaimed in the process. However this is an example specifically crafted
to produce unsatisfying behavior; in all practical usage scenarios the
memory consumption is less than that of a general-purpose allocator because
allocation meta-data is very small in size.
</p>
</div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<b>Object model</b> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="install.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="loading.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,430 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Installation</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="../manual.html" title="pugixml 1.0">
<link rel="next" href="dom.html" title="Document object model">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<b>Installation</b> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="../manual.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="dom.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.install"></a><a class="link" href="install.html" title="Installation"> Installation</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="install.html#manual.install.getting"> Getting pugixml</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="install.html#manual.install.getting.source"> Source distributions</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.getting.subversion"> Subversion repository</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="install.html#manual.install.building"> Building pugixml</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="install.html#manual.install.building.embed"> Building pugixml as
a part of another static library/executable</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.static"> Building pugixml as
a standalone static library</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.shared"> Building pugixml as
a standalone shared library</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.config"> Additional configuration
options</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="install.html#manual.install.portability"> Portability</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.install.getting"></a><a class="link" href="install.html#manual.install.getting" title="Getting pugixml"> Getting pugixml</a>
</h3></div></div></div>
<p>
pugixml is distributed in source form. You can either download a source distribution
or checkout the Subversion repository.
</p>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.getting.source"></a><a class="link" href="install.html#manual.install.getting.source" title="Source distributions"> Source distributions</a>
</h4></div></div></div>
<p>
You can download the latest source distribution via one of the following
links:
</p>
<pre class="programlisting"><a href="http://pugixml.googlecode.com/files/pugixml-1.0.zip" target="_top">http://pugixml.googlecode.com/files/pugixml-1.0.zip</a>
<a href="http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz" target="_top">http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz</a>
</pre>
<p>
The distribution contains library source, documentation (the manual you're
reading now and the quick start guide) and some code examples. After downloading
the distribution, install pugixml by extracting all files from the compressed
archive. The files have different line endings depending on the archive
format - <code class="filename">.zip</code> archive has Windows line endings, <code class="filename">.tar.gz</code> archive has Unix
line endings. Otherwise the files in both archives are identical.
</p>
<p>
If you need an older version, you can download it from the <a href="http://code.google.com/p/pugixml/downloads/list" target="_top">version
archive</a>.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.getting.subversion"></a><a class="link" href="install.html#manual.install.getting.subversion" title="Subversion repository"> Subversion repository</a>
</h4></div></div></div>
<p>
The Subversion repository is located at <a href="http://pugixml.googlecode.com/svn/" target="_top">http://pugixml.googlecode.com/svn/</a>.
There is a Subversion tag "release-{version}" for each version;
also there is the "latest" tag, which always points to the latest
stable release.
</p>
<p>
For example, to checkout the current version, you can use this command:
</p>
<pre class="programlisting">svn checkout http://pugixml.googlecode.com/svn/tags/release-1.0 pugixml</pre>
<p>
To checkout the latest version, you can use this command:
</p>
<pre class="programlisting">svn checkout http://pugixml.googlecode.com/svn/tags/latest pugixml</pre>
<p>
The repository contains library source, documentation, code examples and
full unit test suite.
</p>
<p>
Use latest version tag if you want to automatically get new versions via
<code class="literal">svn update</code>. Use other tags if you want to switch to
new versions only explicitly (for example, using <code class="literal">svn switch</code>
command). Also please note that Subversion trunk contains the work-in-progress
version of the code; while this means that you can get new features and
bug fixes from trunk without waiting for a new release, this also means
that occasionally the code can be broken in some configurations.
</p>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.install.building"></a><a class="link" href="install.html#manual.install.building" title="Building pugixml"> Building pugixml</a>
</h3></div></div></div>
<p>
pugixml is distributed in source form without any pre-built binaries; you
have to build them yourself.
</p>
<p>
The complete pugixml source consists of three files - one source file, <code class="filename">pugixml.cpp</code>,
and two header files, <code class="filename">pugixml.hpp</code> and <code class="filename">pugiconfig.hpp</code>. <code class="filename">pugixml.hpp</code> is the primary
header which you need to include in order to use pugixml classes/functions;
<code class="filename">pugiconfig.hpp</code> is a supplementary configuration file (see <a class="xref" href="install.html#manual.install.building.config" title="Additional configuration options"> Additional configuration
options</a>).
The rest of this guide assumes that <code class="filename">pugixml.hpp</code> is either in the current directory
or in one of include directories of your projects, so that <code class="computeroutput"><span class="preprocessor">#include</span> <span class="string">"pugixml.hpp"</span></code>
can find the header; however you can also use relative path (i.e. <code class="computeroutput"><span class="preprocessor">#include</span> <span class="string">"../libs/pugixml/src/pugixml.hpp"</span></code>)
or include directory-relative path (i.e. <code class="computeroutput"><span class="preprocessor">#include</span>
<span class="special">&lt;</span><span class="identifier">xml</span><span class="special">/</span><span class="identifier">thirdparty</span><span class="special">/</span><span class="identifier">pugixml</span><span class="special">/</span><span class="identifier">src</span><span class="special">/</span><span class="identifier">pugixml</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code>).
</p>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.building.embed"></a><a class="link" href="install.html#manual.install.building.embed" title="Building pugixml as a part of another static library/executable"> Building pugixml as
a part of another static library/executable</a>
</h4></div></div></div>
<p>
The easiest way to build pugixml is to compile the source file, <code class="filename">pugixml.cpp</code>,
along with the existing library/executable. This process depends on the
method of building your application; for example, if you're using Microsoft
Visual Studio<sup>[<a name="trademarks" href="#ftn.trademarks" class="footnote">1</a>]</sup>, Apple Xcode, Code::Blocks or any other IDE, just add <code class="filename">pugixml.cpp</code> to
one of your projects.
</p>
<p>
If you're using Microsoft Visual Studio and the project has precompiled
headers turned on, you'll see the following error messages:
</p>
<pre class="programlisting">pugixml.cpp(3477) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?</pre>
<p>
The correct way to resolve this is to disable precompiled headers for <code class="filename">pugixml.cpp</code>;
you have to set "Create/Use Precompiled Header" option (Properties
dialog -&gt; C/C++ -&gt; Precompiled Headers -&gt; Create/Use Precompiled
Header) to "Not Using Precompiled Headers". You'll have to do
it for all project configurations/platforms (you can select Configuration
"All Configurations" and Platform "All Platforms" before
editing the option):
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<p>
<a href="../images/vs2005_pch1.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_pch1_thumb.png" alt="vs2005_pch1_thumb"></span></a> <span class="inlinemediaobject"><img src="../images/next.png" alt="next"></span> <a href="../images/vs2005_pch2.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_pch2_thumb.png" alt="vs2005_pch2_thumb"></span></a> <span class="inlinemediaobject"><img src="../images/next.png" alt="next"></span> <a href="../images/vs2005_pch3.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_pch3_thumb.png" alt="vs2005_pch3_thumb"></span></a> <span class="inlinemediaobject"><img src="../images/next.png" alt="next"></span> <a href="../images/vs2005_pch4.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_pch4_thumb.png" alt="vs2005_pch4_thumb"></span></a>
</p>
</td></tr></tbody>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.building.static"></a><a class="link" href="install.html#manual.install.building.static" title="Building pugixml as a standalone static library"> Building pugixml as
a standalone static library</a>
</h4></div></div></div>
<p>
It's possible to compile pugixml as a standalone static library. This process
depends on the method of building your application; pugixml distribution
comes with project files for several popular IDEs/build systems. There
are project files for Apple XCode3, Code::Blocks, Codelite, Microsoft Visual
Studio 2005, 2008, 2010, and configuration scripts for CMake and premake4.
You're welcome to submit project files/build scripts for other software;
see <a class="xref" href="../manual.html#manual.overview.feedback" title="Feedback"> Feedback</a>.
</p>
<p>
There are two projects for each version of Microsoft Visual Studio: one
for dynamically linked CRT, which has a name like <code class="filename">pugixml_vs2008.vcproj</code>,
and another one for statically linked CRT, which has a name like <code class="filename">pugixml_vs2008_static.vcproj</code>.
You should select the version that matches the CRT used in your application;
the default option for new projects created by Microsoft Visual Studio
is dynamically linked CRT, so unless you changed the defaults, you should
use the version with dynamic CRT (i.e. <code class="filename">pugixml_vs2008.vcproj</code> for Microsoft
Visual Studio 2008).
</p>
<p>
In addition to adding pugixml project to your workspace, you'll have to
make sure that your application links with pugixml library. If you're using
Microsoft Visual Studio 2005/2008, you can add a dependency from your application
project to pugixml one. If you're using Microsoft Visual Studio 2010, you'll
have to add a reference to your application project instead. For other
IDEs/systems, consult the relevant documentation.
</p>
<div class="informaltable"><table class="table">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Microsoft Visual Studio 2005/2008
</p>
</th>
<th>
<p>
Microsoft Visual Studio 2010
</p>
</th>
</tr></thead>
<tbody><tr>
<td>
<p>
<a href="../images/vs2005_link1.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_link1_thumb.png" alt="vs2005_link1_thumb"></span></a> <span class="inlinemediaobject"><img src="../images/next.png" alt="next"></span> <a href="../images/vs2005_link2.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2005_link2_thumb.png" alt="vs2005_link2_thumb"></span></a>
</p>
</td>
<td>
<p>
<a href="../images/vs2010_link1.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2010_link1_thumb.png" alt="vs2010_link1_thumb"></span></a> <span class="inlinemediaobject"><img src="../images/next.png" alt="next"></span> <a href="../images/vs2010_link2.png" target="_top"><span class="inlinemediaobject"><img src="../images/vs2010_link2_thumb.png" alt="vs2010_link2_thumb"></span></a>
</p>
</td>
</tr></tbody>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.building.shared"></a><a class="link" href="install.html#manual.install.building.shared" title="Building pugixml as a standalone shared library"> Building pugixml as
a standalone shared library</a>
</h4></div></div></div>
<p>
It's possible to compile pugixml as a standalone shared library. The process
is usually similar to the static library approach; however, no preconfigured
projects/scripts are included into pugixml distribution, so you'll have
to do it yourself. Generally, if you're using GCC-based toolchain, the
process does not differ from building any other library as DLL (adding
-shared to compilation flags should suffice); if you're using MSVC-based
toolchain, you'll have to explicitly mark exported symbols with a declspec
attribute. You can do it by defining <a class="link" href="install.html#PUGIXML_API">PUGIXML_API</a>
macro, i.e. via <code class="filename">pugiconfig.hpp</code>:
</p>
<pre class="programlisting"><span class="preprocessor">#ifdef</span> <span class="identifier">_DLL</span>
<span class="preprocessor">#define</span> <span class="identifier">PUGIXML_API</span> <span class="identifier">__declspec</span><span class="special">(</span><span class="identifier">dllexport</span><span class="special">)</span>
<span class="preprocessor">#else</span>
<span class="preprocessor">#define</span> <span class="identifier">PUGIXML_API</span> <span class="identifier">__declspec</span><span class="special">(</span><span class="identifier">dllimport</span><span class="special">)</span>
<span class="preprocessor">#endif</span>
</pre>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
If you're using STL-related functions, you should use the shared runtime
library to ensure that a single heap is used for STL allocations in your
application and in pugixml; in MSVC, this means selecting the 'Multithreaded
DLL' or 'Multithreaded Debug DLL' to 'Runtime library' property (/MD
or /MDd linker switch). You should also make sure that your runtime library
choice is consistent between different projects.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="manual.install.building.config"></a><a class="link" href="install.html#manual.install.building.config" title="Additional configuration options"> Additional configuration
options</a>
</h4></div></div></div>
<p>
pugixml uses several defines to control the compilation process. There
are two ways to define them: either put the needed definitions to <code class="filename">pugiconfig.hpp</code> (it
has some examples that are commented out) or provide them via compiler
command-line. Consistency is important: the definitions should match in
all source files that include <code class="filename">pugixml.hpp</code> (including pugixml sources) throughout
the application. Adding defines to <code class="filename">pugiconfig.hpp</code> lets you guarantee this,
unless your macro definition is wrapped in preprocessor <code class="computeroutput"><span class="preprocessor">#if</span></code>/<code class="computeroutput"><span class="preprocessor">#ifdef</span></code> directive and this directive
is not consistent. <code class="filename">pugiconfig.hpp</code> will never contain anything but comments,
which means that when upgrading to a new version, you can safely leave
your modified version intact.
</p>
<p>
<a name="PUGIXML_WCHAR_MODE"></a><code class="literal">PUGIXML_WCHAR_MODE</code> define toggles
between UTF-8 style interface (the in-memory text encoding is assumed to
be UTF-8, most functions use <code class="computeroutput"><span class="keyword">char</span></code>
as character type) and UTF-16/32 style interface (the in-memory text encoding
is assumed to be UTF-16/32, depending on <code class="computeroutput"><span class="keyword">wchar_t</span></code>
size, most functions use <code class="computeroutput"><span class="keyword">wchar_t</span></code>
as character type). See <a class="xref" href="dom.html#manual.dom.unicode" title="Unicode interface"> Unicode interface</a> for more details.
</p>
<p>
<a name="PUGIXML_NO_XPATH"></a><code class="literal">PUGIXML_NO_XPATH</code> define disables XPath.
Both XPath interfaces and XPath implementation are excluded from compilation.
This option is provided in case you do not need XPath functionality and
need to save code space.
</p>
<p>
<a name="PUGIXML_NO_STL"></a><code class="literal">PUGIXML_NO_STL</code> define disables use of
STL in pugixml. The functions that operate on STL types are no longer present
(i.e. load/save via iostream) if this macro is defined. This option is
provided in case your target platform does not have a standard-compliant
STL implementation.
</p>
<p>
<a name="PUGIXML_NO_EXCEPTIONS"></a><code class="literal">PUGIXML_NO_EXCEPTIONS</code> define disables
use of exceptions in pugixml. This option is provided in case your target
platform does not have exception handling capabilities.
</p>
<p>
<a name="PUGIXML_API"></a><code class="literal">PUGIXML_API</code>, <a name="PUGIXML_CLASS"></a><code class="literal">PUGIXML_CLASS</code>
and <a name="PUGIXML_FUNCTION"></a><code class="literal">PUGIXML_FUNCTION</code> defines let you
specify custom attributes (i.e. declspec or calling conventions) for pugixml
classes and non-member functions. In absence of <code class="computeroutput"><span class="identifier">PUGIXML_CLASS</span></code>
or <code class="computeroutput"><span class="identifier">PUGIXML_FUNCTION</span></code> definitions,
<code class="computeroutput"><span class="identifier">PUGIXML_API</span></code> definition
is used instead. For example, to specify fixed calling convention, you
can define <code class="computeroutput"><span class="identifier">PUGIXML_FUNCTION</span></code>
to i.e. <code class="computeroutput"><span class="identifier">__fastcall</span></code>. Another
example is DLL import/export attributes in MSVC (see <a class="xref" href="install.html#manual.install.building.shared" title="Building pugixml as a standalone shared library"> Building pugixml as
a standalone shared library</a>).
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
In that example <code class="computeroutput"><span class="identifier">PUGIXML_API</span></code>
is inconsistent between several source files; this is an exception to
the consistency rule.
</p></td></tr>
</table></div>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.install.portability"></a><a class="link" href="install.html#manual.install.portability" title="Portability"> Portability</a>
</h3></div></div></div>
<p>
pugixml is written in standard-compliant C++ with some compiler-specific
workarounds where appropriate. pugixml is compatible with the upcoming C++0x
standard (verified using GCC 4.5). Each version is tested with a unit test
suite (with code coverage about 99%) on the following platforms:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Microsoft Windows:
<div class="itemizedlist"><ul class="itemizedlist" type="circle">
<li class="listitem">
Borland C++ Compiler 5.82
</li>
<li class="listitem">
Digital Mars C++ Compiler 8.51
</li>
<li class="listitem">
Intel C++ Compiler 8.0, 9.0 x86/x64, 10.0 x86/x64, 11.0 x86/x64
</li>
<li class="listitem">
Metrowerks CodeWarrior 8.0
</li>
<li class="listitem">
Microsoft Visual C++ 6.0, 7.0 (2002), 7.1 (2003), 8.0 (2005) x86/x64,
9.0 (2008) x86/x64, 10.0 (2010) x86/x64
</li>
<li class="listitem">
MinGW (GCC) 3.4, 4.4, 4.5, 4.6 x64
</li>
</ul></div>
</li>
<li class="listitem">
Linux (GCC 4.4.3 x86/x64)
</li>
<li class="listitem">
FreeBSD (GCC 4.2.1 x86/x64)
</li>
<li class="listitem">
Apple MacOSX (GCC 4.0.1 x86/x64/PowerPC)
</li>
<li class="listitem">
Microsoft Xbox 360
</li>
<li class="listitem">
Nintendo Wii (Metrowerks CodeWarrior 4.1)
</li>
<li class="listitem">
Sony Playstation Portable (GCC 3.4.2)
</li>
<li class="listitem">
Sony Playstation 3 (GCC 4.1.1, SNC 310.1)
</li>
</ul></div>
</div>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.trademarks" href="#trademarks" class="para">1</a>] </sup>All trademarks used are properties of their respective
owners.</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<b>Installation</b> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="../manual.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="dom.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,853 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Loading document</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="dom.html" title="Document object model">
<link rel="next" href="access.html" title="Accessing document data">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <b>Loading</b> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="dom.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="access.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.loading"></a><a class="link" href="loading.html" title="Loading document"> Loading document</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="loading.html#manual.loading.file"> Loading document from file</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.memory"> Loading document from memory</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.stream"> Loading document from C++ IOstreams</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.errors"> Handling parsing errors</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.options"> Parsing options</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.encoding"> Encodings</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.w3c"> Conformance to W3C specification</a></span></dt>
</dl></div>
<p>
pugixml provides several functions for loading XML data from various places
- files, C++ iostreams, memory buffers. All functions use an extremely fast
non-validating parser. This parser is not fully W3C conformant - it can load
any valid XML document, but does not perform some well-formedness checks. While
considerable effort is made to reject invalid XML documents, some validation
is not performed for performance reasons. Also some XML transformations (i.e.
EOL handling or attribute value normalization) can impact parsing speed and
thus can be disabled. However for vast majority of XML documents there is no
performance difference between different parsing options. Parsing options also
control whether certain XML nodes are parsed; see <a class="xref" href="loading.html#manual.loading.options" title="Parsing options"> Parsing options</a> for
more information.
</p>
<p>
XML data is always converted to internal character format (see <a class="xref" href="dom.html#manual.dom.unicode" title="Unicode interface"> Unicode interface</a>)
before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16
(big and little endian), UTF-32 (big and little endian); UCS-2 is naturally
supported since it's a strict subset of UTF-16) and handles all encoding conversions
automatically. Unless explicit encoding is specified, loading functions perform
automatic encoding detection based on first few characters of XML data, so
in almost all cases you do not have to specify document encoding. Encoding
conversion is described in more detail in <a class="xref" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a>.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.file"></a><a class="link" href="loading.html#manual.loading.file" title="Loading document from file"> Loading document from file</a>
</h3></div></div></div>
<a name="xml_document::load_file"></a><a name="xml_document::load_file_wide"></a><p>
The most common source of XML data is files; pugixml provides dedicated functions
for loading an XML document from file:
</p>
<pre class="programlisting"><span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_file</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
<span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_file</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> <span class="identifier">path</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
</pre>
<p>
These functions accept the file path as its first argument, and also two
optional arguments, which specify parsing options (see <a class="xref" href="loading.html#manual.loading.options" title="Parsing options"> Parsing options</a>)
and input data encoding (see <a class="xref" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a>). The path has the target
operating system format, so it can be a relative or absolute one, it should
have the delimiters of the target system, it should have the exact case if
the target file system is case-sensitive, etc.
</p>
<p>
File path is passed to the system file opening function as is in case of
the first function (which accepts <code class="computeroutput"><span class="keyword">const</span>
<span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span></code>); the second function either uses
a special file opening function if it is provided by the runtime library
or converts the path to UTF-8 and uses the system file opening function.
</p>
<p>
<code class="computeroutput"><span class="identifier">load_file</span></code> destroys the existing
document tree and then tries to load the new tree from the specified file.
The result of the operation is returned in an <a class="link" href="loading.html#xml_parse_result">xml_parse_result</a>
object; this object contains the operation status and the related information
(i.e. last successfully parsed position in the input file, if parsing fails).
See <a class="xref" href="loading.html#manual.loading.errors" title="Handling parsing errors"> Handling parsing errors</a> for error handling details.
</p>
<p>
This is an example of loading XML document from file (<a href="../samples/load_file.cpp" target="_top">samples/load_file.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_file</span><span class="special">(</span><span class="string">"tree.xml"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Load result: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">description</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">", mesh name: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"mesh"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.memory"></a><a class="link" href="loading.html#manual.loading.memory" title="Loading document from memory"> Loading document from memory</a>
</h3></div></div></div>
<a name="xml_document::load_buffer"></a><a name="xml_document::load_buffer_inplace"></a><a name="xml_document::load_buffer_inplace_own"></a><p>
Sometimes XML data should be loaded from some other source than a file, i.e.
HTTP URL; also you may want to load XML data from file using non-standard
functions, i.e. to use your virtual file system facilities or to load XML
from gzip-compressed files. All these scenarios require loading document
from memory. First you should prepare a contiguous memory block with all
XML data; then you have to invoke one of buffer loading functions. These
functions will handle the necessary encoding conversions, if any, and then
will parse the data into the corresponding XML tree. There are several buffer
loading functions, which differ in the behavior and thus in performance/memory
usage:
</p>
<pre class="programlisting"><span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_buffer</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">void</span><span class="special">*</span> <span class="identifier">contents</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
<span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_buffer_inplace</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">contents</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
<span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_buffer_inplace_own</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">contents</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
</pre>
<p>
All functions accept the buffer which is represented by a pointer to XML
data, <code class="computeroutput"><span class="identifier">contents</span></code>, and data
size in bytes. Also there are two optional arguments, which specify parsing
options (see <a class="xref" href="loading.html#manual.loading.options" title="Parsing options"> Parsing options</a>) and input data encoding (see <a class="xref" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a>).
The buffer does not have to be zero-terminated.
</p>
<p>
<code class="computeroutput"><span class="identifier">load_buffer</span></code> function works
with immutable buffer - it does not ever modify the buffer. Because of this
restriction it has to create a private buffer and copy XML data to it before
parsing (applying encoding conversions if necessary). This copy operation
carries a performance penalty, so inplace functions are provided - <code class="computeroutput"><span class="identifier">load_buffer_inplace</span></code> and <code class="computeroutput"><span class="identifier">load_buffer_inplace_own</span></code>
store the document data in the buffer, modifying it in the process. In order
for the document to stay valid, you have to make sure that the buffer's lifetime
exceeds that of the tree if you're using inplace functions. In addition to
that, <code class="computeroutput"><span class="identifier">load_buffer_inplace</span></code>
does not assume ownership of the buffer, so you'll have to destroy it yourself;
<code class="computeroutput"><span class="identifier">load_buffer_inplace_own</span></code> assumes
ownership of the buffer and destroys it once it is not needed. This means
that if you're using <code class="computeroutput"><span class="identifier">load_buffer_inplace_own</span></code>,
you have to allocate memory with pugixml allocation function (you can get
it via <a class="link" href="dom.html#get_memory_allocation_function">get_memory_allocation_function</a>).
</p>
<p>
The best way from the performance/memory point of view is to load document
using <code class="computeroutput"><span class="identifier">load_buffer_inplace_own</span></code>;
this function has maximum control of the buffer with XML data so it is able
to avoid redundant copies and reduce peak memory usage while parsing. This
is the recommended function if you have to load the document from memory
and performance is critical.
</p>
<a name="xml_document::load_string"></a><p>
There is also a simple helper function for cases when you want to load the
XML document from null-terminated character string:
</p>
<pre class="programlisting"><span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">contents</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">);</span>
</pre>
<p>
It is equivalent to calling <code class="computeroutput"><span class="identifier">load_buffer</span></code>
with <code class="computeroutput"><span class="identifier">size</span></code> being either <code class="computeroutput"><span class="identifier">strlen</span><span class="special">(</span><span class="identifier">contents</span><span class="special">)</span></code>
or <code class="computeroutput"><span class="identifier">wcslen</span><span class="special">(</span><span class="identifier">contents</span><span class="special">)</span> <span class="special">*</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="keyword">wchar_t</span><span class="special">)</span></code>,
depending on the character type. This function assumes native encoding for
input data, so it does not do any encoding conversion. In general, this function
is fine for loading small documents from string literals, but has more overhead
and less functionality than the buffer loading functions.
</p>
<p>
This is an example of loading XML document from memory using different functions
(<a href="../samples/load_memory.cpp" target="_top">samples/load_memory.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="keyword">char</span> <span class="identifier">source</span><span class="special">[]</span> <span class="special">=</span> <span class="string">"&lt;mesh name='sphere'&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;"</span><span class="special">;</span>
<span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">source</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// You can use load_buffer to load document from immutable memory block:
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_buffer</span><span class="special">(</span><span class="identifier">source</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
</span><span class="keyword">char</span><span class="special">*</span> <span class="identifier">buffer</span> <span class="special">=</span> <span class="keyword">new</span> <span class="keyword">char</span><span class="special">[</span><span class="identifier">size</span><span class="special">];</span>
<span class="identifier">memcpy</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">source</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
<span class="comment">// The block can be allocated by any method; the block is modified during parsing
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_buffer_inplace</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
<span class="comment">// You have to destroy the block yourself after the document is no longer used
</span><span class="keyword">delete</span><span class="special">[]</span> <span class="identifier">buffer</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block
</span><span class="comment">// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect
</span><span class="keyword">char</span><span class="special">*</span> <span class="identifier">buffer</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">*&gt;(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">get_memory_allocation_function</span><span class="special">()(</span><span class="identifier">size</span><span class="special">));</span>
<span class="identifier">memcpy</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">source</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
<span class="comment">// The block will be deleted by the document
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_buffer_inplace_own</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// You can use load to load document from null-terminated strings, for example literals:
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="string">"&lt;mesh name='sphere'&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;"</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.stream"></a><a class="link" href="loading.html#manual.loading.stream" title="Loading document from C++ IOstreams"> Loading document from C++ IOstreams</a>
</h3></div></div></div>
<a name="xml_document::load_stream"></a><p>
To enhance interoperability, pugixml provides functions for loading document
from any object which implements C++ <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code>
interface. This allows you to load documents from any standard C++ stream
(i.e. file stream) or any third-party compliant implementation (i.e. Boost
Iostreams). There are two functions, one works with narrow character streams,
another handles wide character ones:
</p>
<pre class="programlisting"><span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">);</span>
<span class="identifier">xml_parse_result</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">wistream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">options</span> <span class="special">=</span> <span class="identifier">parse_default</span><span class="special">);</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">load</span></code> with <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code>
argument loads the document from stream from the current read position to
the end, treating the stream contents as a byte stream of the specified encoding
(with encoding autodetection as necessary). Thus calling <code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load</span></code>
on an opened <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ifstream</span></code> object is equivalent to calling
<code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load_file</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">load</span></code> with <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wstream</span></code>
argument treats the stream contents as a wide character stream (encoding
is always <a class="link" href="loading.html#encoding_wchar">encoding_wchar</a>). Because
of this, using <code class="computeroutput"><span class="identifier">load</span></code> with
wide character streams requires careful (usually platform-specific) stream
setup (i.e. using the <code class="computeroutput"><span class="identifier">imbue</span></code>
function). Generally use of wide streams is discouraged, however it provides
you the ability to load documents from non-Unicode encodings, i.e. you can
load Shift-JIS encoded data if you set the correct locale.
</p>
<p>
This is a simple example of loading XML document from file using streams
(<a href="../samples/load_stream.cpp" target="_top">samples/load_stream.cpp</a>); read
the sample code for more complex examples involving wide streams and locales:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ifstream</span> <span class="identifier">stream</span><span class="special">(</span><span class="string">"weekly-utf-8.xml"</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">stream</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
Stream loading requires working seek/tell functions and therefore may fail
when used with some stream implementations like gzstream.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.errors"></a><a class="link" href="loading.html#manual.loading.errors" title="Handling parsing errors"> Handling parsing errors</a>
</h3></div></div></div>
<a name="xml_parse_result"></a><p>
All document loading functions return the parsing result via <code class="computeroutput"><span class="identifier">xml_parse_result</span></code> object. It contains parsing
status, the offset of last successfully parsed character from the beginning
of the source stream, and the encoding of the source stream:
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">xml_parse_result</span>
<span class="special">{</span>
<span class="identifier">xml_parse_status</span> <span class="identifier">status</span><span class="special">;</span>
<span class="identifier">ptrdiff_t</span> <span class="identifier">offset</span><span class="special">;</span>
<span class="identifier">xml_encoding</span> <span class="identifier">encoding</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="keyword">bool</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">description</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<a name="xml_parse_status"></a><a name="xml_parse_result::status"></a><p>
Parsing status is represented as the <code class="computeroutput"><span class="identifier">xml_parse_status</span></code>
enumeration and can be one of the following:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="status_ok"></a><code class="literal">status_ok</code> means that no error was encountered
during parsing; the source stream represents the valid XML document which
was fully parsed and converted to a tree. <br><br>
</li>
<li class="listitem">
<a name="status_file_not_found"></a><code class="literal">status_file_not_found</code> is only
returned by <code class="computeroutput"><span class="identifier">load_file</span></code>
function and means that file could not be opened.
</li>
<li class="listitem">
<a name="status_io_error"></a><code class="literal">status_io_error</code> is returned by <code class="computeroutput"><span class="identifier">load_file</span></code> function and by <code class="computeroutput"><span class="identifier">load</span></code> functions with <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code>/<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wstream</span></code> arguments; it means that some
I/O error has occurred during reading the file/stream.
</li>
<li class="listitem">
<a name="status_out_of_memory"></a><code class="literal">status_out_of_memory</code> means that
there was not enough memory during some allocation; any allocation failure
during parsing results in this error.
</li>
<li class="listitem">
<a name="status_internal_error"></a><code class="literal">status_internal_error</code> means that
something went horribly wrong; currently this error does not occur <br><br>
</li>
<li class="listitem">
<a name="status_unrecognized_tag"></a><code class="literal">status_unrecognized_tag</code> means
that parsing stopped due to a tag with either an empty name or a name
which starts with incorrect character, such as <code class="literal">#</code>.
</li>
<li class="listitem">
<a name="status_bad_pi"></a><code class="literal">status_bad_pi</code> means that parsing stopped
due to incorrect document declaration/processing instruction
</li>
<li class="listitem">
<a name="status_bad_comment"></a><code class="literal">status_bad_comment</code>, <a name="status_bad_cdata"></a><code class="literal">status_bad_cdata</code>,
<a name="status_bad_doctype"></a><code class="literal">status_bad_doctype</code> and <a name="status_bad_pcdata"></a><code class="literal">status_bad_pcdata</code>
mean that parsing stopped due to the invalid construct of the respective
type
</li>
<li class="listitem">
<a name="status_bad_start_element"></a><code class="literal">status_bad_start_element</code> means
that parsing stopped because starting tag either had no closing <code class="computeroutput"><span class="special">&gt;</span></code> symbol or contained some incorrect
symbol
</li>
<li class="listitem">
<a name="status_bad_attribute"></a><code class="literal">status_bad_attribute</code> means that
parsing stopped because there was an incorrect attribute, such as an
attribute without value or with value that is not quoted (note that
<code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span>
<span class="identifier">attr</span><span class="special">=</span><span class="number">1</span><span class="special">&gt;</span></code> is
incorrect in XML)
</li>
<li class="listitem">
<a name="status_bad_end_element"></a><code class="literal">status_bad_end_element</code> means
that parsing stopped because ending tag had incorrect syntax (i.e. extra
non-whitespace symbols between tag name and <code class="computeroutput"><span class="special">&gt;</span></code>)
</li>
<li class="listitem">
<a name="status_end_element_mismatch"></a><code class="literal">status_end_element_mismatch</code>
means that parsing stopped because the closing tag did not match the
opening one (i.e. <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;&lt;/</span><span class="identifier">nedo</span><span class="special">&gt;</span></code>) or because some tag was not closed
at all
</li>
</ul></div>
<a name="xml_parse_result::description"></a><p>
<code class="computeroutput"><span class="identifier">description</span><span class="special">()</span></code>
member function can be used to convert parsing status to a string; the returned
message is always in English, so you'll have to write your own function if
you need a localized string. However please note that the exact messages
returned by <code class="computeroutput"><span class="identifier">description</span><span class="special">()</span></code>
function may change from version to version, so any complex status handling
should be based on <code class="computeroutput"><span class="identifier">status</span></code>
value.
</p>
<p>
If parsing failed because the source data was not a valid XML, the resulting
tree is not destroyed - despite the fact that load function returns error,
you can use the part of the tree that was successfully parsed. Obviously,
the last element may have an unexpected name/value; for example, if the attribute
value does not end with the necessary quotation mark, like in <code class="literal">&lt;node
attr="value&gt;some data&lt;/node&gt;</code> example, the value of
attribute <code class="computeroutput"><span class="identifier">attr</span></code> will contain
the string <code class="computeroutput"><span class="identifier">value</span><span class="special">&gt;</span><span class="identifier">some</span> <span class="identifier">data</span><span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span></code>.
</p>
<a name="xml_parse_result::offset"></a><p>
In addition to the status code, parsing result has an <code class="computeroutput"><span class="identifier">offset</span></code>
member, which contains the offset of last successfully parsed character if
parsing failed because of an error in source data; otherwise <code class="computeroutput"><span class="identifier">offset</span></code> is 0. For parsing efficiency reasons,
pugixml does not track the current line during parsing; this offset is in
units of <a class="link" href="dom.html#char_t">pugi::char_t</a> (bytes for character
mode, wide characters for wide character mode). Many text editors support
'Go To Position' feature - you can use it to locate the exact error position.
Alternatively, if you're loading the document from memory, you can display
the error chunk along with the error description (see the example code below).
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
Offset is calculated in the XML buffer in native encoding; if encoding
conversion is performed during parsing, offset can not be used to reliably
track the error position.
</p></td></tr>
</table></div>
<a name="xml_parse_result::encoding"></a><p>
Parsing result also has an <code class="computeroutput"><span class="identifier">encoding</span></code>
member, which can be used to check that the source data encoding was correctly
guessed. It is equal to the exact encoding used during parsing (i.e. with
the exact endianness); see <a class="xref" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a> for more information.
</p>
<a name="xml_parse_result::bool"></a><p>
Parsing result object can be implicitly converted to <code class="computeroutput"><span class="keyword">bool</span></code>;
if you do not want to handle parsing errors thoroughly, you can just check
the return value of load functions as if it was a <code class="computeroutput"><span class="keyword">bool</span></code>:
<code class="computeroutput"><span class="keyword">if</span> <span class="special">(</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_file</span><span class="special">(</span><span class="string">"file.xml"</span><span class="special">))</span> <span class="special">{</span> <span class="special">...</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>.
</p>
<p>
This is an example of handling loading errors (<a href="../samples/load_error_handling.cpp" target="_top">samples/load_error_handling.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">result</span><span class="special">)</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"XML ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span> <span class="special">&lt;&lt;</span> <span class="string">"] parsed without errors, attr value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"attr"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n\n"</span><span class="special">;</span>
<span class="keyword">else</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"XML ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span> <span class="special">&lt;&lt;</span> <span class="string">"] parsed with errors, attr value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"attr"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Error description: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">description</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Error offset: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">offset</span> <span class="special">&lt;&lt;</span> <span class="string">" (error at [..."</span> <span class="special">&lt;&lt;</span> <span class="special">(</span><span class="identifier">source</span> <span class="special">+</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">offset</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.options"></a><a class="link" href="loading.html#manual.loading.options" title="Parsing options"> Parsing options</a>
</h3></div></div></div>
<p>
All document loading functions accept the optional parameter <code class="computeroutput"><span class="identifier">options</span></code>. This is a bitmask that customizes
the parsing process: you can select the node types that are parsed and various
transformations that are performed with the XML text. Disabling certain transformations
can improve parsing performance for some documents; however, the code for
all transformations is very well optimized, and thus the majority of documents
won't get any performance benefit. As a rule of thumb, only modify parsing
flags if you want to get some nodes in the document that are excluded by
default (i.e. declaration or comment nodes).
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
You should use the usual bitwise arithmetics to manipulate the bitmask:
to enable a flag, use <code class="computeroutput"><span class="identifier">mask</span> <span class="special">|</span> <span class="identifier">flag</span></code>;
to disable a flag, use <code class="computeroutput"><span class="identifier">mask</span> <span class="special">&amp;</span> <span class="special">~</span><span class="identifier">flag</span></code>.
</p></td></tr>
</table></div>
<p>
These flags control the resulting tree contents:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="parse_declaration"></a><code class="literal">parse_declaration</code> determines if XML
document declaration (node with type <a class="link" href="dom.html#node_declaration">node_declaration</a>)
is to be put in DOM tree. If this flag is off, it is not put in the tree,
but is still parsed and checked for correctness. This flag is <span class="bold"><strong>off</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_doctype"></a><code class="literal">parse_doctype</code> determines if XML document
type declaration (node with type <a class="link" href="dom.html#node_doctype">node_doctype</a>)
is to be put in DOM tree. If this flag is off, it is not put in the tree,
but is still parsed and checked for correctness. This flag is <span class="bold"><strong>off</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_pi"></a><code class="literal">parse_pi</code> determines if processing instructions
(nodes with type <a class="link" href="dom.html#node_pi">node_pi</a>) are to be put
in DOM tree. If this flag is off, they are not put in the tree, but are
still parsed and checked for correctness. Note that <code class="computeroutput"><span class="special">&lt;?</span><span class="identifier">xml</span> <span class="special">...?&gt;</span></code>
(document declaration) is not considered to be a PI. This flag is <span class="bold"><strong>off</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_comments"></a><code class="literal">parse_comments</code> determines if comments
(nodes with type <a class="link" href="dom.html#node_comment">node_comment</a>) are
to be put in DOM tree. If this flag is off, they are not put in the tree,
but are still parsed and checked for correctness. This flag is <span class="bold"><strong>off</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_cdata"></a><code class="literal">parse_cdata</code> determines if CDATA sections
(nodes with type <a class="link" href="dom.html#node_cdata">node_cdata</a>) are to
be put in DOM tree. If this flag is off, they are not put in the tree,
but are still parsed and checked for correctness. This flag is <span class="bold"><strong>on</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_ws_pcdata"></a><code class="literal">parse_ws_pcdata</code> determines if PCDATA
nodes (nodes with type <a class="link" href="dom.html#node_pcdata">node_pcdata</a>)
that consist only of whitespace characters are to be put in DOM tree.
Often whitespace-only data is not significant for the application, and
the cost of allocating and storing such nodes (both memory and speed-wise)
can be significant. For example, after parsing XML string <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span> <span class="special">&lt;</span><span class="identifier">a</span><span class="special">/&gt;</span> <span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span></code>, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span></code>
element will have three children when <code class="computeroutput"><span class="identifier">parse_ws_pcdata</span></code>
is set (child with type <a class="link" href="dom.html#node_pcdata">node_pcdata</a>
and value <code class="computeroutput"><span class="string">" "</span></code>,
child with type <a class="link" href="dom.html#node_element">node_element</a> and
name <code class="computeroutput"><span class="string">"a"</span></code>, and another
child with type <a class="link" href="dom.html#node_pcdata">node_pcdata</a> and value
<code class="computeroutput"><span class="string">" "</span></code>), and only
one child when <code class="computeroutput"><span class="identifier">parse_ws_pcdata</span></code>
is not set. This flag is <span class="bold"><strong>off</strong></span> by default.
</li>
</ul></div>
<p>
These flags control the transformation of tree element contents:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="parse_escapes"></a><code class="literal">parse_escapes</code> determines if character
and entity references are to be expanded during the parsing process.
Character references have the form <code class="literal">&amp;#...;</code> or
<code class="literal">&amp;#x...;</code> (<code class="literal">...</code> is Unicode numeric
representation of character in either decimal (<code class="literal">&amp;#...;</code>)
or hexadecimal (<code class="literal">&amp;#x...;</code>) form), entity references
are <code class="literal">&amp;lt;</code>, <code class="literal">&amp;gt;</code>, <code class="literal">&amp;amp;</code>,
<code class="literal">&amp;apos;</code> and <code class="literal">&amp;quot;</code> (note
that as pugixml does not handle DTD, the only allowed entities are predefined
ones). If character/entity reference can not be expanded, it is left
as is, so you can do additional processing later. Reference expansion
is performed on attribute values and PCDATA content. This flag is <span class="bold"><strong>on</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="parse_eol"></a><code class="literal">parse_eol</code> determines if EOL handling (that
is, replacing sequences <code class="computeroutput"><span class="number">0x0d</span> <span class="number">0x0a</span></code> by a single <code class="computeroutput"><span class="number">0x0a</span></code>
character, and replacing all standalone <code class="computeroutput"><span class="number">0x0d</span></code>
characters by <code class="computeroutput"><span class="number">0x0a</span></code>) is to
be performed on input data (that is, comments contents, PCDATA/CDATA
contents and attribute values). This flag is <span class="bold"><strong>on</strong></span>
by default. <br><br>
</li>
<li class="listitem">
<a name="parse_wconv_attribute"></a><code class="literal">parse_wconv_attribute</code> determines
if attribute value normalization should be performed for all attributes.
This means, that whitespace characters (new line, tab and space) are
replaced with space (<code class="computeroutput"><span class="char">' '</span></code>).
New line characters are always treated as if <a class="link" href="loading.html#parse_eol">parse_eol</a>
is set, i.e. <code class="computeroutput"><span class="special">\</span><span class="identifier">r</span><span class="special">\</span><span class="identifier">n</span></code>
is converted to a single space. This flag is <span class="bold"><strong>on</strong></span>
by default. <br><br>
</li>
<li class="listitem">
<a name="parse_wnorm_attribute"></a><code class="literal">parse_wnorm_attribute</code> determines
if extended attribute value normalization should be performed for all
attributes. This means, that after attribute values are normalized as
if <a class="link" href="loading.html#parse_wconv_attribute">parse_wconv_attribute</a>
was set, leading and trailing space characters are removed, and all sequences
of space characters are replaced by a single space character. The value
of <a class="link" href="loading.html#parse_wconv_attribute">parse_wconv_attribute</a>
has no effect if this flag is on. This flag is <span class="bold"><strong>off</strong></span>
by default.
</li>
</ul></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
<code class="computeroutput"><span class="identifier">parse_wconv_attribute</span></code> option
performs transformations that are required by W3C specification for attributes
that are declared as <code class="literal">CDATA</code>; <a class="link" href="loading.html#parse_wnorm_attribute">parse_wnorm_attribute</a>
performs transformations required for <code class="literal">NMTOKENS</code> attributes.
In the absence of document type declaration all attributes should behave
as if they are declared as <code class="literal">CDATA</code>, thus <a class="link" href="loading.html#parse_wconv_attribute">parse_wconv_attribute</a>
is the default option.
</p></td></tr>
</table></div>
<p>
Additionally there are three predefined option masks:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="parse_minimal"></a><code class="literal">parse_minimal</code> has all options turned
off. This option mask means that pugixml does not add declaration nodes,
document type declaration nodes, PI nodes, CDATA sections and comments
to the resulting tree and does not perform any conversion for input data,
so theoretically it is the fastest mode. However, as mentioned above,
in practice <a class="link" href="loading.html#parse_default">parse_default</a> is usually
equally fast. <br><br>
</li>
<li class="listitem">
<a name="parse_default"></a><code class="literal">parse_default</code> is the default set of flags,
i.e. it has all options set to their default values. It includes parsing
CDATA sections (comments/PIs are not parsed), performing character and
entity reference expansion, replacing whitespace characters with spaces
in attribute values and performing EOL handling. Note, that PCDATA sections
consisting only of whitespace characters are not parsed (by default)
for performance reasons. <br><br>
</li>
<li class="listitem">
<a name="parse_full"></a><code class="literal">parse_full</code> is the set of flags which adds
nodes of all types to the resulting tree and performs default conversions
for input data. It includes parsing CDATA sections, comments, PI nodes,
document declaration node and document type declaration node, performing
character and entity reference expansion, replacing whitespace characters
with spaces in attribute values and performing EOL handling. Note, that
PCDATA sections consisting only of whitespace characters are not parsed
in this mode.
</li>
</ul></div>
<p>
This is an example of using different parsing options (<a href="../samples/load_options.cpp" target="_top">samples/load_options.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">source</span> <span class="special">=</span> <span class="string">"&lt;!--comment--&gt;&lt;node&gt;&amp;lt;&lt;/node&gt;"</span><span class="special">;</span>
<span class="comment">// Parsing with default options; note that comment node is not added to the tree, and entity reference &amp;lt; is expanded
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"First node value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"], node child value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"node"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
<span class="comment">// Parsing with additional parse_comments option; comment node is now added to the tree
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_default</span> <span class="special">|</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_comments</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"First node value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"], node child value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"node"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
<span class="comment">// Parsing with additional parse_comments option and without the (default) parse_escapes option; &amp;lt; is not expanded
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">,</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_default</span> <span class="special">|</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_comments</span><span class="special">)</span> <span class="special">&amp;</span> <span class="special">~</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_escapes</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"First node value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"], node child value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"node"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
<span class="comment">// Parsing with minimal option mask; comment node is not added to the tree, and &amp;lt; is not expanded
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_minimal</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"First node value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"], node child value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"node"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.encoding"></a><a class="link" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a>
</h3></div></div></div>
<a name="xml_encoding"></a><p>
pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little
endian), UTF-32 (big and little endian); UCS-2 is naturally supported since
it's a strict subset of UTF-16) and handles all encoding conversions. Most
loading functions accept the optional parameter <code class="computeroutput"><span class="identifier">encoding</span></code>.
This is a value of enumeration type <code class="computeroutput"><span class="identifier">xml_encoding</span></code>,
that can have the following values:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="encoding_auto"></a><code class="literal">encoding_auto</code> means that pugixml will
try to guess the encoding based on source XML data. The algorithm is
a modified version of the one presented in Appendix F.1 of XML recommendation;
it tries to match the first few bytes of input data with the following
patterns in strict order: <br><br>
<div class="itemizedlist"><ul class="itemizedlist" type="circle">
<li class="listitem">
If first four bytes match UTF-32 BOM (Byte Order Mark), encoding
is assumed to be UTF-32 with the endianness equal to that of BOM;
</li>
<li class="listitem">
If first two bytes match UTF-16 BOM, encoding is assumed to be
UTF-16 with the endianness equal to that of BOM;
</li>
<li class="listitem">
If first three bytes match UTF-8 BOM, encoding is assumed to be
UTF-8;
</li>
<li class="listitem">
If first four bytes match UTF-32 representation of <code class="literal">&lt;</code>,
encoding is assumed to be UTF-32 with the corresponding endianness;
</li>
<li class="listitem">
If first four bytes match UTF-16 representation of <code class="literal">&lt;?</code>,
encoding is assumed to be UTF-16 with the corresponding endianness;
</li>
<li class="listitem">
If first two bytes match UTF-16 representation of <code class="literal">&lt;</code>,
encoding is assumed to be UTF-16 with the corresponding endianness
(this guess may yield incorrect result, but it's better than UTF-8);
</li>
<li class="listitem">
Otherwise encoding is assumed to be UTF-8. <br><br>
</li>
</ul></div>
</li>
<li class="listitem">
<a name="encoding_utf8"></a><code class="literal">encoding_utf8</code> corresponds to UTF-8 encoding
as defined in the Unicode standard; UTF-8 sequences with length equal
to 5 or 6 are not standard and are rejected.
</li>
<li class="listitem">
<a name="encoding_utf16_le"></a><code class="literal">encoding_utf16_le</code> corresponds to
little-endian UTF-16 encoding as defined in the Unicode standard; surrogate
pairs are supported.
</li>
<li class="listitem">
<a name="encoding_utf16_be"></a><code class="literal">encoding_utf16_be</code> corresponds to
big-endian UTF-16 encoding as defined in the Unicode standard; surrogate
pairs are supported.
</li>
<li class="listitem">
<a name="encoding_utf16"></a><code class="literal">encoding_utf16</code> corresponds to UTF-16
encoding as defined in the Unicode standard; the endianness is assumed
to be that of the target platform.
</li>
<li class="listitem">
<a name="encoding_utf32_le"></a><code class="literal">encoding_utf32_le</code> corresponds to
little-endian UTF-32 encoding as defined in the Unicode standard.
</li>
<li class="listitem">
<a name="encoding_utf32_be"></a><code class="literal">encoding_utf32_be</code> corresponds to
big-endian UTF-32 encoding as defined in the Unicode standard.
</li>
<li class="listitem">
<a name="encoding_utf32"></a><code class="literal">encoding_utf32</code> corresponds to UTF-32
encoding as defined in the Unicode standard; the endianness is assumed
to be that of the target platform.
</li>
<li class="listitem">
<a name="encoding_wchar"></a><code class="literal">encoding_wchar</code> corresponds to the encoding
of <code class="computeroutput"><span class="keyword">wchar_t</span></code> type; it has
the same meaning as either <code class="computeroutput"><span class="identifier">encoding_utf16</span></code>
or <code class="computeroutput"><span class="identifier">encoding_utf32</span></code>, depending
on <code class="computeroutput"><span class="keyword">wchar_t</span></code> size.
</li>
</ul></div>
<p>
The algorithm used for <code class="computeroutput"><span class="identifier">encoding_auto</span></code>
correctly detects any supported Unicode encoding for all well-formed XML
documents (since they start with document declaration) and for all other
XML documents that start with <code class="literal">&lt;</code>; if your XML document
does not start with <code class="literal">&lt;</code> and has encoding that is different
from UTF-8, use the specific encoding.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The current behavior for Unicode conversion is to skip all invalid UTF
sequences during conversion. This behavior should not be relied upon; moreover,
in case no encoding conversion is performed, the invalid sequences are
not removed, so you'll get them as is in node/attribute contents.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.loading.w3c"></a><a class="link" href="loading.html#manual.loading.w3c" title="Conformance to W3C specification"> Conformance to W3C specification</a>
</h3></div></div></div>
<p>
pugixml is not fully W3C conformant - it can load any valid XML document,
but does not perform some well-formedness checks. While considerable effort
is made to reject invalid XML documents, some validation is not performed
because of performance reasons.
</p>
<p>
There is only one non-conformant behavior when dealing with valid XML documents:
pugixml does not use information supplied in document type declaration for
parsing. This means that entities declared in DOCTYPE are not expanded, and
all attribute/PCDATA values are always processed in a uniform way that depends
only on parsing options.
</p>
<p>
As for rejecting invalid XML documents, there are a number of incompatibilities
with W3C specification, including:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Multiple attributes of the same node can have equal names.
</li>
<li class="listitem">
All non-ASCII characters are treated in the same way as symbols of English
alphabet, so some invalid tag names are not rejected.
</li>
<li class="listitem">
Attribute values which contain <code class="literal">&lt;</code> are not rejected.
</li>
<li class="listitem">
Invalid entity/character references are not rejected and are instead
left as is.
</li>
<li class="listitem">
Comment values can contain <code class="literal">--</code>.
</li>
<li class="listitem">
XML data is not required to begin with document declaration; additionally,
document declaration can appear after comments and other nodes.
</li>
<li class="listitem">
Invalid document type declarations are silently ignored in some cases.
</li>
</ul></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <b>Loading</b> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="dom.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="access.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,553 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Modifying document data</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="access.html" title="Accessing document data">
<link rel="next" href="saving.html" title="Saving document">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <b>Modifying</b> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="access.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="saving.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.modify"></a><a class="link" href="modify.html" title="Modifying document data"> Modifying document data</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="modify.html#manual.modify.nodedata"> Setting node data</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.attrdata"> Setting attribute data</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.add"> Adding nodes/attributes</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.remove"> Removing nodes/attributes</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.clone"> Cloning nodes/attributes</a></span></dt>
</dl></div>
<p>
The document in pugixml is fully mutable: you can completely change the document
structure and modify the data of nodes/attributes. This section provides documentation
for the relevant functions. All functions take care of memory management and
structural integrity themselves, so they always result in structurally valid
tree - however, it is possible to create an invalid XML tree (for example,
by adding two attributes with the same name or by setting attribute/node name
to empty/invalid string). Tree modification is optimized for performance and
for memory consumption, so if you have enough memory you can create documents
from scratch with pugixml and later save them to file/stream instead of relying
on error-prone manual text writing and without too much overhead.
</p>
<p>
All member functions that change node/attribute data or structure are non-constant
and thus can not be called on constant handles. However, you can easily convert
constant handle to non-constant one by simple assignment: <code class="computeroutput"><span class="keyword">void</span>
<span class="identifier">foo</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span>
<span class="special">{</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">nc</span> <span class="special">=</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">}</span></code>, so const-correctness
here mainly provides additional documentation.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.modify.nodedata"></a><a class="link" href="modify.html#manual.modify.nodedata" title="Setting node data"> Setting node data</a>
</h3></div></div></div>
<a name="xml_node::set_name"></a><a name="xml_node::set_value"></a><p>
As discussed before, nodes can have name and value, both of which are strings.
Depending on node type, name or value may be absent. <a class="link" href="dom.html#node_document">node_document</a>
nodes do not have a name or value, <a class="link" href="dom.html#node_element">node_element</a>
and <a class="link" href="dom.html#node_declaration">node_declaration</a> nodes always
have a name but never have a value, <a class="link" href="dom.html#node_pcdata">node_pcdata</a>,
<a class="link" href="dom.html#node_cdata">node_cdata</a>, <a class="link" href="dom.html#node_comment">node_comment</a>
and <a class="link" href="dom.html#node_doctype">node_doctype</a> nodes never have a name
but always have a value (it may be empty though), <a class="link" href="dom.html#node_pi">node_pi</a>
nodes always have a name and a value (again, value may be empty). In order
to set node's name or value, you can use the following functions:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">set_name</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">rhs</span><span class="special">);</span>
</pre>
<p>
Both functions try to set the name/value to the specified string, and return
the operation result. The operation fails if the node can not have name or
value (for instance, when trying to call <code class="computeroutput"><span class="identifier">set_name</span></code>
on a <a class="link" href="dom.html#node_pcdata">node_pcdata</a> node), if the node handle
is null, or if there is insufficient memory to handle the request. The provided
string is copied into document managed memory and can be destroyed after
the function returns (for example, you can safely pass stack-allocated buffers
to these functions). The name/value content is not verified, so take care
to use only valid XML names, or the document may become malformed.
</p>
<p>
There is no equivalent of <a class="link" href="access.html#xml_node::child_value">child_value</a>
function for modifying text children of the node.
</p>
<p>
This is an example of setting node name and value (<a href="../samples/modify_base.cpp" target="_top">samples/modify_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="comment">// change node name
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"notnode"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new node name: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// change comment text
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"useless comment"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new comment text: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can't change value of the element or name of the comment
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"1"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">", "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"2"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.modify.attrdata"></a><a class="link" href="modify.html#manual.modify.attrdata" title="Setting attribute data"> Setting attribute data</a>
</h3></div></div></div>
<a name="xml_attribute::set_name"></a><a name="xml_attribute::set_value"></a><p>
All attributes have name and value, both of which are strings (value may
be empty). You can set them with the following functions:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_name</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">rhs</span><span class="special">);</span>
</pre>
<p>
Both functions try to set the name/value to the specified string, and return
the operation result. The operation fails if the attribute handle is null,
or if there is insufficient memory to handle the request. The provided string
is copied into document managed memory and can be destroyed after the function
returns (for example, you can safely pass stack-allocated buffers to these
functions). The name/value content is not verified, so take care to use only
valid XML names, or the document may become malformed.
</p>
<p>
In addition to string functions, several functions are provided for handling
attributes with numbers and booleans as values:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="identifier">set_value</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">rhs</span><span class="special">);</span>
</pre>
<p>
The above functions convert the argument to string and then call the base
<code class="computeroutput"><span class="identifier">set_value</span></code> function. Integers
are converted to a decimal form, floating-point numbers are converted to
either decimal or scientific form, depending on the number magnitude, boolean
values are converted to either <code class="computeroutput"><span class="string">"true"</span></code>
or <code class="computeroutput"><span class="string">"false"</span></code>.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
Number conversion functions depend on current C locale as set with <code class="computeroutput"><span class="identifier">setlocale</span></code>, so may generate unexpected
results if the locale is different from <code class="computeroutput"><span class="string">"C"</span></code>.
</p></td></tr>
</table></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
There are no portable 64-bit types in C++, so there is no corresponding
<code class="computeroutput"><span class="identifier">set_value</span></code> function. If
your platform has a 64-bit integer, you can easily write such a function
yourself.
</p></td></tr>
</table></div>
<a name="xml_attribute::assign"></a><p>
For convenience, all <code class="computeroutput"><span class="identifier">set_value</span></code>
functions have the corresponding assignment operators:
</p>
<pre class="programlisting"><span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="keyword">operator</span><span class="special">=(</span><span class="keyword">int</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="keyword">operator</span><span class="special">=(</span><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="keyword">operator</span><span class="special">=(</span><span class="keyword">double</span> <span class="identifier">rhs</span><span class="special">);</span>
<span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">xml_attribute</span><span class="special">::</span><span class="keyword">operator</span><span class="special">=(</span><span class="keyword">bool</span> <span class="identifier">rhs</span><span class="special">);</span>
</pre>
<p>
These operators simply call the right <code class="computeroutput"><span class="identifier">set_value</span></code>
function and return the attribute they're called on; the return value of
<code class="computeroutput"><span class="identifier">set_value</span></code> is ignored, so
errors are ignored.
</p>
<p>
This is an example of setting attribute name and value (<a href="../samples/modify_base.cpp" target="_top">samples/modify_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"id"</span><span class="special">);</span>
<span class="comment">// change attribute name/value
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"key"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">", "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"345"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new attribute: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"="</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can use numbers or booleans
</span><span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="number">1.234</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"new attribute value: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can also use assignment operators for more concise code
</span><span class="identifier">attr</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"final attribute value: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.modify.add"></a><a class="link" href="modify.html#manual.modify.add" title="Adding nodes/attributes"> Adding nodes/attributes</a>
</h3></div></div></div>
<a name="xml_node::prepend_attribute"></a><a name="xml_node::append_attribute"></a><a name="xml_node::insert_attribute_after"></a><a name="xml_node::insert_attribute_before"></a><a name="xml_node::prepend_child"></a><a name="xml_node::append_child"></a><a name="xml_node::insert_child_after"></a><a name="xml_node::insert_child_before"></a><p>
Nodes and attributes do not exist without a document tree, so you can't create
them without adding them to some document. A node or attribute can be created
at the end of node/attribute list or before/after some other node:
</p>
<pre class="programlisting"><span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">append_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">prepend_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_attribute_after</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_attribute_before</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">append_child</span><span class="special">(</span><span class="identifier">xml_node_type</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">node_element</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">prepend_child</span><span class="special">(</span><span class="identifier">xml_node_type</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">node_element</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_child_after</span><span class="special">(</span><span class="identifier">xml_node_type</span> <span class="identifier">type</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_child_before</span><span class="special">(</span><span class="identifier">xml_node_type</span> <span class="identifier">type</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">append_child</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">prepend_child</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_child_after</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_child_before</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">append_attribute</span></code> and <code class="computeroutput"><span class="identifier">append_child</span></code> create a new node/attribute
at the end of the corresponding list of the node the method is called on;
<code class="computeroutput"><span class="identifier">prepend_attribute</span></code> and <code class="computeroutput"><span class="identifier">prepend_child</span></code> create a new node/attribute
at the beginning of the list; <code class="computeroutput"><span class="identifier">insert_attribute_after</span></code>,
<code class="computeroutput"><span class="identifier">insert_attribute_before</span></code>,
<code class="computeroutput"><span class="identifier">insert_child_after</span></code> and <code class="computeroutput"><span class="identifier">insert_attribute_before</span></code> add the node/attribute
before or after the specified node/attribute.
</p>
<p>
Attribute functions create an attribute with the specified name; you can
specify the empty name and change the name later if you want to. Node functions
with the <code class="computeroutput"><span class="identifier">type</span></code> argument create
the node with the specified type; since node type can't be changed, you have
to know the desired type beforehand. Also note that not all types can be
added as children; see below for clarification. Node functions with the
<code class="computeroutput"><span class="identifier">name</span></code> argument create the
element node (<a class="link" href="dom.html#node_element">node_element</a>) with the
specified name.
</p>
<p>
All functions return the handle to the created object on success, and null
handle on failure. There are several reasons for failure:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Adding fails if the target node is null;
</li>
<li class="listitem">
Only <a class="link" href="dom.html#node_element">node_element</a> nodes can contain
attributes, so attribute adding fails if node is not an element;
</li>
<li class="listitem">
Only <a class="link" href="dom.html#node_document">node_document</a> and <a class="link" href="dom.html#node_element">node_element</a>
nodes can contain children, so child node adding fails if the target
node is not an element or a document;
</li>
<li class="listitem">
<a class="link" href="dom.html#node_document">node_document</a> and <a class="link" href="dom.html#node_null">node_null</a>
nodes can not be inserted as children, so passing <a class="link" href="dom.html#node_document">node_document</a>
or <a class="link" href="dom.html#node_null">node_null</a> value as <code class="computeroutput"><span class="identifier">type</span></code> results in operation failure;
</li>
<li class="listitem">
<a class="link" href="dom.html#node_declaration">node_declaration</a> nodes can only
be added as children of the document node; attempt to insert declaration
node as a child of an element node fails;
</li>
<li class="listitem">
Adding node/attribute results in memory allocation, which may fail;
</li>
<li class="listitem">
Insertion functions fail if the specified node or attribute is null or
is not in the target node's children/attribute list.
</li>
</ul></div>
<p>
Even if the operation fails, the document remains in consistent state, but
the requested node/attribute is not added.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
attribute() and child() functions do not add attributes or nodes to the
tree, so code like <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"id"</span><span class="special">)</span> <span class="special">=</span> <span class="number">123</span><span class="special">;</span></code> will not do anything if <code class="computeroutput"><span class="identifier">node</span></code> does not have an attribute with
name <code class="computeroutput"><span class="string">"id"</span></code>. Make sure
you're operating with existing attributes/nodes by adding them if necessary.
</p></td></tr>
</table></div>
<p>
This is an example of adding new attributes/nodes to the document (<a href="../samples/modify_add.cpp" target="_top">samples/modify_add.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// add node with some name
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="comment">// add description node with text child
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">descr</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="string">"description"</span><span class="special">);</span>
<span class="identifier">descr</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">node_pcdata</span><span class="special">).</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"Simple node"</span><span class="special">);</span>
<span class="comment">// add param node before the description
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">insert_child_before</span><span class="special">(</span><span class="string">"param"</span><span class="special">,</span> <span class="identifier">descr</span><span class="special">);</span>
<span class="comment">// add attributes to param node
</span><span class="identifier">param</span><span class="special">.</span><span class="identifier">append_attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">)</span> <span class="special">=</span> <span class="string">"version"</span><span class="special">;</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">append_attribute</span><span class="special">(</span><span class="string">"value"</span><span class="special">)</span> <span class="special">=</span> <span class="number">1.1</span><span class="special">;</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">insert_attribute_after</span><span class="special">(</span><span class="string">"type"</span><span class="special">,</span> <span class="identifier">param</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">))</span> <span class="special">=</span> <span class="string">"float"</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.modify.remove"></a><a class="link" href="modify.html#manual.modify.remove" title="Removing nodes/attributes"> Removing nodes/attributes</a>
</h3></div></div></div>
<a name="xml_node::remove_attribute"></a><a name="xml_node::remove_child"></a><p>
If you do not want your document to contain some node or attribute, you can
remove it with one of the following functions:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">a</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">remove_child</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">);</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">remove_attribute</span></code> removes
the attribute from the attribute list of the node, and returns the operation
result. <code class="computeroutput"><span class="identifier">remove_child</span></code> removes
the child node with the entire subtree (including all descendant nodes and
attributes) from the document, and returns the operation result. Removing
fails if one of the following is true:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
The node the function is called on is null;
</li>
<li class="listitem">
The attribute/node to be removed is null;
</li>
<li class="listitem">
The attribute/node to be removed is not in the node's attribute/child
list.
</li>
</ul></div>
<p>
Removing the attribute or node invalidates all handles to the same underlying
object, and also invalidates all iterators pointing to the same object. Removing
node also invalidates all past-the-end iterators to its attribute or child
node list. Be careful to ensure that all such handles and iterators either
do not exist or are not used after the attribute/node is removed.
</p>
<p>
If you want to remove the attribute or child node by its name, two additional
helper functions are available:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">remove_child</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
</pre>
<p>
These functions look for the first attribute or child with the specified
name, and then remove it, returning the result. If there is no attribute
or child with such name, the function returns <code class="computeroutput"><span class="keyword">false</span></code>;
if there are two nodes with the given name, only the first node is deleted.
If you want to delete all nodes with the specified name, you can use code
like this: <code class="computeroutput"><span class="keyword">while</span> <span class="special">(</span><span class="identifier">node</span><span class="special">.</span><span class="identifier">remove_child</span><span class="special">(</span><span class="string">"tool"</span><span class="special">))</span> <span class="special">;</span></code>.
</p>
<p>
This is an example of removing attributes/nodes from the document (<a href="../samples/modify_remove.cpp" target="_top">samples/modify_remove.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// remove description node with the whole subtree
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="identifier">node</span><span class="special">.</span><span class="identifier">remove_child</span><span class="special">(</span><span class="string">"description"</span><span class="special">);</span>
<span class="comment">// remove id attribute
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"param"</span><span class="special">);</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="string">"value"</span><span class="special">);</span>
<span class="comment">// we can also remove nodes/attributes by handles
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">id</span> <span class="special">=</span> <span class="identifier">param</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">);</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="identifier">id</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.modify.clone"></a><a class="link" href="modify.html#manual.modify.clone" title="Cloning nodes/attributes"> Cloning nodes/attributes</a>
</h3></div></div></div>
<a name="xml_node::prepend_copy"></a><a name="xml_node::append_copy"></a><a name="xml_node::insert_copy_after"></a><a name="xml_node::insert_copy_before"></a><p>
With the help of previously described functions, it is possible to create
trees with any contents and structure, including cloning the existing data.
However since this is an often needed operation, pugixml provides built-in
node/attribute cloning facilities. Since nodes and attributes do not exist
without a document tree, you can't create a standalone copy - you have to
immediately insert it somewhere in the tree. For this, you can use one of
the following functions:
</p>
<pre class="programlisting"><span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">append_copy</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">prepend_copy</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_copy_after</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">);</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_copy_before</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_attribute</span><span class="special">&amp;</span> <span class="identifier">attr</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">append_copy</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">prepend_copy</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_copy_after</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
<span class="identifier">xml_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">insert_copy_before</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">proto</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">);</span>
</pre>
<p>
These functions mirror the structure of <code class="computeroutput"><span class="identifier">append_child</span></code>,
<code class="computeroutput"><span class="identifier">prepend_child</span></code>, <code class="computeroutput"><span class="identifier">insert_child_before</span></code> and related functions
- they take the handle to the prototype object, which is to be cloned, insert
a new attribute/node at the appropriate place, and then copy the attribute
data or the whole node subtree to the new object. The functions return the
handle to the resulting duplicate object, or null handle on failure.
</p>
<p>
The attribute is copied along with the name and value; the node is copied
along with its type, name and value; additionally attribute list and all
children are recursively cloned, resulting in the deep subtree clone. The
prototype object can be a part of the same document, or a part of any other
document.
</p>
<p>
The failure conditions resemble those of <code class="computeroutput"><span class="identifier">append_child</span></code>,
<code class="computeroutput"><span class="identifier">insert_child_before</span></code> and related
functions, <a class="link" href="modify.html#xml_node::append_child">consult their documentation
for more information</a>. There are additional caveats specific to cloning
functions:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Cloning null handles results in operation failure;
</li>
<li class="listitem">
Node cloning starts with insertion of the node of the same type as that
of the prototype; for this reason, cloning functions can not be directly
used to clone entire documents, since <a class="link" href="dom.html#node_document">node_document</a>
is not a valid insertion type. The example below provides a workaround.
</li>
<li class="listitem">
It is possible to copy a subtree as a child of some node inside this
subtree, i.e. <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">append_copy</span><span class="special">(</span><span class="identifier">node</span><span class="special">.</span><span class="identifier">parent</span><span class="special">().</span><span class="identifier">parent</span><span class="special">());</span></code>.
This is a valid operation, and it results in a clone of the subtree in
the state before cloning started, i.e. no infinite recursion takes place.
</li>
</ul></div>
<p>
This is an example with one possible implementation of include tags in XML
(<a href="../samples/include.cpp" target="_top">samples/include.cpp</a>). It illustrates
node cloning and usage of other document modification functions:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">load_preprocess</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span><span class="special">&amp;</span> <span class="identifier">doc</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">preprocess</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">child</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">();</span> <span class="identifier">child</span><span class="special">;</span> <span class="special">)</span>
<span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">child</span><span class="special">.</span><span class="identifier">type</span><span class="special">()</span> <span class="special">==</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">node_pi</span> <span class="special">&amp;&amp;</span> <span class="identifier">strcmp</span><span class="special">(</span><span class="identifier">child</span><span class="special">.</span><span class="identifier">name</span><span class="special">(),</span> <span class="string">"include"</span><span class="special">)</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">include</span> <span class="special">=</span> <span class="identifier">child</span><span class="special">;</span>
<span class="comment">// load new preprocessed document (note: ideally this should handle relative paths)
</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span> <span class="special">=</span> <span class="identifier">include</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">load_preprocess</span><span class="special">(</span><span class="identifier">doc</span><span class="special">,</span> <span class="identifier">path</span><span class="special">))</span> <span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span>
<span class="comment">// insert the comment marker above include directive
</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">insert_child_before</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">node_comment</span><span class="special">,</span> <span class="identifier">include</span><span class="special">).</span><span class="identifier">set_value</span><span class="special">(</span><span class="identifier">path</span><span class="special">);</span>
<span class="comment">// copy the document above the include directive (this retains the original order!)
</span> <span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">ic</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_child</span><span class="special">();</span> <span class="identifier">ic</span><span class="special">;</span> <span class="identifier">ic</span> <span class="special">=</span> <span class="identifier">ic</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">())</span>
<span class="special">{</span>
<span class="identifier">node</span><span class="special">.</span><span class="identifier">insert_copy_before</span><span class="special">(</span><span class="identifier">ic</span><span class="special">,</span> <span class="identifier">include</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// remove the include node and move to the next child
</span> <span class="identifier">child</span> <span class="special">=</span> <span class="identifier">child</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">();</span>
<span class="identifier">node</span><span class="special">.</span><span class="identifier">remove_child</span><span class="special">(</span><span class="identifier">include</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">else</span>
<span class="special">{</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">preprocess</span><span class="special">(</span><span class="identifier">child</span><span class="special">))</span> <span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span>
<span class="identifier">child</span> <span class="special">=</span> <span class="identifier">child</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">bool</span> <span class="identifier">load_preprocess</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span><span class="special">&amp;</span> <span class="identifier">doc</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_file</span><span class="special">(</span><span class="identifier">path</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_default</span> <span class="special">|</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">parse_pi</span><span class="special">);</span> <span class="comment">// for &lt;?include?&gt;
</span>
<span class="keyword">return</span> <span class="identifier">result</span> <span class="special">?</span> <span class="identifier">preprocess</span><span class="special">(</span><span class="identifier">doc</span><span class="special">)</span> <span class="special">:</span> <span class="keyword">false</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <b>Modifying</b> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="access.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="saving.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,463 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Saving document</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="modify.html" title="Modifying document data">
<link rel="next" href="xpath.html" title="XPath">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <b>Saving</b> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="modify.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="xpath.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.saving"></a><a class="link" href="saving.html" title="Saving document"> Saving document</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="saving.html#manual.saving.file"> Saving document to a file</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.stream"> Saving document to C++ IOstreams</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.writer"> Saving document via writer interface</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.subtree"> Saving a single subtree</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.options"> Output options</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.encoding"> Encodings</a></span></dt>
</dl></div>
<p>
Often after creating a new document or loading the existing one and processing
it, it is necessary to save the result back to file. Also it is occasionally
useful to output the whole document or a subtree to some stream; use cases
include debug printing, serialization via network or other text-oriented medium,
etc. pugixml provides several functions to output any subtree of the document
to a file, stream or another generic transport interface; these functions allow
to customize the output format (see <a class="xref" href="saving.html#manual.saving.options" title="Output options"> Output options</a>), and also perform
necessary encoding conversions (see <a class="xref" href="saving.html#manual.saving.encoding" title="Encodings"> Encodings</a>). This section documents
the relevant functionality.
</p>
<p>
Before writing to the destination the node/attribute data is properly formatted
according to the node type; all special XML symbols, such as &lt; and &amp;,
are properly escaped. In order to guard against forgotten node/attribute names,
empty node/attribute names are printed as <code class="computeroutput"><span class="string">":anonymous"</span></code>.
For well-formed output, make sure all node and attribute names are set to meaningful
values.
</p>
<p>
CDATA sections with values that contain <code class="computeroutput"><span class="string">"]]&gt;"</span></code>
are split into several sections as follows: section with value <code class="computeroutput"><span class="string">"pre]]&gt;post"</span></code> is written as <code class="computeroutput"><span class="special">&lt;![</span><span class="identifier">CDATA</span><span class="special">[</span><span class="identifier">pre</span><span class="special">]]]]&gt;&lt;![</span><span class="identifier">CDATA</span><span class="special">[&gt;</span><span class="identifier">post</span><span class="special">]]&gt;</span></code>.
While this alters the structure of the document (if you load the document after
saving it, there will be two CDATA sections instead of one), this is the only
way to escape CDATA contents.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.file"></a><a class="link" href="saving.html#manual.saving.file" title="Saving document to a file"> Saving document to a file</a>
</h3></div></div></div>
<a name="xml_document::save_file"></a><a name="xml_document::save_file_wide"></a><p>
If you want to save the whole document to a file, you can use one of the
following functions:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save_file</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save_file</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> <span class="identifier">path</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
These functions accept file path as its first argument, and also three optional
arguments, which specify indentation and other output options (see <a class="xref" href="saving.html#manual.saving.options" title="Output options"> Output options</a>)
and output data encoding (see <a class="xref" href="saving.html#manual.saving.encoding" title="Encodings"> Encodings</a>). The path has the target
operating system format, so it can be a relative or absolute one, it should
have the delimiters of the target system, it should have the exact case if
the target file system is case-sensitive, etc.
</p>
<p>
File path is passed to the system file opening function as is in case of
the first function (which accepts <code class="computeroutput"><span class="keyword">const</span>
<span class="keyword">char</span><span class="special">*</span> <span class="identifier">path</span></code>); the second function either uses
a special file opening function if it is provided by the runtime library
or converts the path to UTF-8 and uses the system file opening function.
</p>
<a name="xml_writer_file"></a><p>
<code class="computeroutput"><span class="identifier">save_file</span></code> opens the target
file for writing, outputs the requested header (by default a document declaration
is output, unless the document already has one), and then saves the document
contents. If the file could not be opened, the function returns <code class="computeroutput"><span class="keyword">false</span></code>. Calling <code class="computeroutput"><span class="identifier">save_file</span></code>
is equivalent to creating an <code class="computeroutput"><span class="identifier">xml_writer_file</span></code>
object with <code class="computeroutput"><span class="identifier">FILE</span><span class="special">*</span></code>
handle as the only constructor argument and then calling <code class="computeroutput"><span class="identifier">save</span></code>;
see <a class="xref" href="saving.html#manual.saving.writer" title="Saving document via writer interface"> Saving document via writer interface</a> for writer interface details.
</p>
<p>
This is a simple example of saving XML document to file (<a href="../samples/save_file.cpp" target="_top">samples/save_file.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// save document to file
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Saving result: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">save_file</span><span class="special">(</span><span class="string">"save_file_output.xml"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.stream"></a><a class="link" href="saving.html#manual.saving.stream" title="Saving document to C++ IOstreams"> Saving document to C++ IOstreams</a>
</h3></div></div></div>
<a name="xml_document::save_stream"></a><p>
To enhance interoperability pugixml provides functions for saving document
to any object which implements C++ <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>
interface. This allows you to save documents to any standard C++ stream (i.e.
file stream) or any third-party compliant implementation (i.e. Boost Iostreams).
Most notably, this allows for easy debug output, since you can use <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>
stream as saving target. There are two functions, one works with narrow character
streams, another handles wide character ones:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">wostream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">save</span></code> with <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>
argument saves the document to the stream in the same way as <code class="computeroutput"><span class="identifier">save_file</span></code> (i.e. with requested header and
with encoding conversions). On the other hand, <code class="computeroutput"><span class="identifier">save</span></code>
with <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wstream</span></code> argument saves the document to
the wide stream with <a class="link" href="loading.html#encoding_wchar">encoding_wchar</a>
encoding. Because of this, using <code class="computeroutput"><span class="identifier">save</span></code>
with wide character streams requires careful (usually platform-specific)
stream setup (i.e. using the <code class="computeroutput"><span class="identifier">imbue</span></code>
function). Generally use of wide streams is discouraged, however it provides
you with the ability to save documents to non-Unicode encodings, i.e. you
can save Shift-JIS encoded data if you set the correct locale.
</p>
<a name="xml_writer_stream"></a><p>
Calling <code class="computeroutput"><span class="identifier">save</span></code> with stream
target is equivalent to creating an <code class="computeroutput"><span class="identifier">xml_writer_stream</span></code>
object with stream as the only constructor argument and then calling <code class="computeroutput"><span class="identifier">save</span></code>; see <a class="xref" href="saving.html#manual.saving.writer" title="Saving document via writer interface"> Saving document via writer interface</a> for writer
interface details.
</p>
<p>
This is a simple example of saving XML document to standard output (<a href="../samples/save_stream.cpp" target="_top">samples/save_stream.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// save document to standard output
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Document:\n"</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.writer"></a><a class="link" href="saving.html#manual.saving.writer" title="Saving document via writer interface"> Saving document via writer interface</a>
</h3></div></div></div>
<a name="xml_document::save"></a><a name="xml_writer"></a><a name="xml_writer::write"></a><p>
All of the above saving functions are implemented in terms of writer interface.
This is a simple interface with a single function, which is called several
times during output process with chunks of document data as input:
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">xml_writer</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">write</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">void</span><span class="special">*</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">void</span> <span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">xml_writer</span><span class="special">&amp;</span> <span class="identifier">writer</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
In order to output the document via some custom transport, for example sockets,
you should create an object which implements <code class="computeroutput"><span class="identifier">xml_writer_file</span></code>
interface and pass it to <code class="computeroutput"><span class="identifier">save</span></code>
function. <code class="computeroutput"><span class="identifier">xml_writer_file</span><span class="special">::</span><span class="identifier">write</span></code>
function is called with a buffer as an input, where <code class="computeroutput"><span class="identifier">data</span></code>
points to buffer start, and <code class="computeroutput"><span class="identifier">size</span></code>
is equal to the buffer size in bytes. <code class="computeroutput"><span class="identifier">write</span></code>
implementation must write the buffer to the transport; it can not save the
passed buffer pointer, as the buffer contents will change after <code class="computeroutput"><span class="identifier">write</span></code> returns. The buffer contains the
chunk of document data in the desired encoding.
</p>
<p>
<code class="computeroutput"><span class="identifier">write</span></code> function is called
with relatively large blocks (size is usually several kilobytes, except for
the first block with BOM, which is output only if <a class="link" href="saving.html#format_write_bom">format_write_bom</a>
is set, and last block, which may be small), so there is often no need for
additional buffering in the implementation.
</p>
<p>
This is a simple example of custom writer for saving document data to STL
string (<a href="../samples/save_custom_writer.cpp" target="_top">samples/save_custom_writer.cpp</a>);
read the sample code for more complex examples:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">xml_string_writer</span><span class="special">:</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_writer</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span><span class="special">;</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">write</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">void</span><span class="special">*</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">result</span> <span class="special">+=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*&gt;(</span><span class="identifier">data</span><span class="special">),</span> <span class="identifier">size</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.subtree"></a><a class="link" href="saving.html#manual.saving.subtree" title="Saving a single subtree"> Saving a single subtree</a>
</h3></div></div></div>
<a name="xml_node::print"></a><a name="xml_node::print_stream"></a><p>
While the previously described functions save the whole document to the destination,
it is easy to save a single subtree. The following functions are provided:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">&amp;</span> <span class="identifier">os</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">depth</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">wostream</span><span class="special">&amp;</span> <span class="identifier">os</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">depth</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">xml_writer</span><span class="special">&amp;</span> <span class="identifier">writer</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">indent</span> <span class="special">=</span> <span class="string">"\t"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">flags</span> <span class="special">=</span> <span class="identifier">format_default</span><span class="special">,</span> <span class="identifier">xml_encoding</span> <span class="identifier">encoding</span> <span class="special">=</span> <span class="identifier">encoding_auto</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">depth</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
These functions have the same arguments with the same meaning as the corresponding
<code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span></code> functions, and allow you to save the
subtree to either a C++ IOstream or to any object that implements <code class="computeroutput"><span class="identifier">xml_writer</span></code> interface.
</p>
<p>
Saving a subtree differs from saving the whole document: the process behaves
as if <a class="link" href="saving.html#format_write_bom">format_write_bom</a> is off, and
<a class="link" href="saving.html#format_no_declaration">format_no_declaration</a> is on,
even if actual values of the flags are different. This means that BOM is
not written to the destination, and document declaration is only written
if it is the node itself or is one of node's children. Note that this also
holds if you're saving a document; this example (<a href="../samples/save_subtree.cpp" target="_top">samples/save_subtree.cpp</a>)
illustrates the difference:
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// get a test document
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="string">"&lt;foo bar='baz'&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;"</span><span class="special">);</span>
<span class="comment">// print document to standard output (prints &lt;?xml version="1.0"?&gt;&lt;foo bar="baz"&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;)
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">""</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_raw</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// print document to standard output as a regular node (prints &lt;foo bar="baz"&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;)
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">""</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_raw</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// print a subtree to standard output (prints &lt;call&gt;hey&lt;/call&gt;)
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"foo"</span><span class="special">).</span><span class="identifier">child</span><span class="special">(</span><span class="string">"call"</span><span class="special">).</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">""</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_raw</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.options"></a><a class="link" href="saving.html#manual.saving.options" title="Output options"> Output options</a>
</h3></div></div></div>
<p>
All saving functions accept the optional parameter <code class="computeroutput"><span class="identifier">flags</span></code>.
This is a bitmask that customizes the output format; you can select the way
the document nodes are printed and select the needed additional information
that is output before the document contents.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
You should use the usual bitwise arithmetics to manipulate the bitmask:
to enable a flag, use <code class="computeroutput"><span class="identifier">mask</span> <span class="special">|</span> <span class="identifier">flag</span></code>;
to disable a flag, use <code class="computeroutput"><span class="identifier">mask</span> <span class="special">&amp;</span> <span class="special">~</span><span class="identifier">flag</span></code>.
</p></td></tr>
</table></div>
<p>
These flags control the resulting tree contents:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="format_indent"></a><code class="literal">format_indent</code> determines if all nodes
should be indented with the indentation string (this is an additional
parameter for all saving functions, and is <code class="computeroutput"><span class="string">"\t"</span></code>
by default). If this flag is on, before every node the indentation string
is output several times, where the amount of indentation depends on the
node's depth relative to the output subtree. This flag has no effect
if <a class="link" href="saving.html#format_raw">format_raw</a> is enabled. This flag
is <span class="bold"><strong>on</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="format_raw"></a><code class="literal">format_raw</code> switches between formatted and
raw output. If this flag is on, the nodes are not indented in any way,
and also no newlines that are not part of document text are printed.
Raw mode can be used for serialization where the result is not intended
to be read by humans; also it can be useful if the document was parsed
with <a class="link" href="loading.html#parse_ws_pcdata">parse_ws_pcdata</a> flag, to
preserve the original document formatting as much as possible. This flag
is <span class="bold"><strong>off</strong></span> by default.
</li>
</ul></div>
<p>
These flags control the additional output information:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<a name="format_no_declaration"></a><code class="literal">format_no_declaration</code> disables
default node declaration output. By default, if the document is saved
via <code class="computeroutput"><span class="identifier">save</span></code> or <code class="computeroutput"><span class="identifier">save_file</span></code> function, and it does not
have any document declaration, a default declaration is output before
the document contents. Enabling this flag disables this declaration.
This flag has no effect in <code class="computeroutput"><span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span></code>
functions: they never output the default declaration. This flag is <span class="bold"><strong>off</strong></span> by default. <br><br>
</li>
<li class="listitem">
<a name="format_write_bom"></a><code class="literal">format_write_bom</code> enables Byte Order
Mark (BOM) output. By default, no BOM is output, so in case of non UTF-8
encodings the resulting document's encoding may not be recognized by
some parsers and text editors, if they do not implement sophisticated
encoding detection. Enabling this flag adds an encoding-specific BOM
to the output. This flag has no effect in <code class="computeroutput"><span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span></code>
functions: they never output the BOM. This flag is <span class="bold"><strong>off</strong></span>
by default.
</li>
</ul></div>
<p>
Additionally, there is one predefined option mask:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
<a name="format_default"></a><code class="literal">format_default</code> is the default set of
flags, i.e. it has all options set to their default values. It sets formatted
output with indentation, without BOM and with default node declaration,
if necessary.
</li></ul></div>
<p>
This is an example that shows the outputs of different output options (<a href="../samples/save_options.cpp" target="_top">samples/save_options.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// get a test document
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="string">"&lt;foo bar='baz'&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;"</span><span class="special">);</span>
<span class="comment">// default options; prints
</span><span class="comment">// &lt;?xml version="1.0"?&gt;
</span><span class="comment">// &lt;foo bar="baz"&gt;
</span><span class="comment">// &lt;call&gt;hey&lt;/call&gt;
</span><span class="comment">// &lt;/foo&gt;
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// default options with custom indentation string; prints
</span><span class="comment">// &lt;?xml version="1.0"?&gt;
</span><span class="comment">// &lt;foo bar="baz"&gt;
</span><span class="comment">// --&lt;call&gt;hey&lt;/call&gt;
</span><span class="comment">// &lt;/foo&gt;
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">"--"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// default options without indentation; prints
</span><span class="comment">// &lt;?xml version="1.0"?&gt;
</span><span class="comment">// &lt;foo bar="baz"&gt;
</span><span class="comment">// &lt;call&gt;hey&lt;/call&gt;
</span><span class="comment">// &lt;/foo&gt;
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">"\t"</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_default</span> <span class="special">&amp;</span> <span class="special">~</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_indent</span><span class="special">);</span> <span class="comment">// can also pass "" instead of indentation string for the same effect
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// raw output; prints
</span><span class="comment">// &lt;?xml version="1.0"?&gt;&lt;foo bar="baz"&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">"\t"</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_raw</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// raw output without declaration; prints
</span><span class="comment">// &lt;foo bar="baz"&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;
</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">,</span> <span class="string">"\t"</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_raw</span> <span class="special">|</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">format_no_declaration</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.saving.encoding"></a><a class="link" href="saving.html#manual.saving.encoding" title="Encodings"> Encodings</a>
</h3></div></div></div>
<p>
pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little
endian), UTF-32 (big and little endian); UCS-2 is naturally supported since
it's a strict subset of UTF-16) and handles all encoding conversions during
output. The output encoding is set via the <code class="computeroutput"><span class="identifier">encoding</span></code>
parameter of saving functions, which is of type <code class="computeroutput"><span class="identifier">xml_encoding</span></code>.
The possible values for the encoding are documented in <a class="xref" href="loading.html#manual.loading.encoding" title="Encodings"> Encodings</a>;
the only flag that has a different meaning is <code class="computeroutput"><span class="identifier">encoding_auto</span></code>.
</p>
<p>
While all other flags set the exact encoding, <code class="computeroutput"><span class="identifier">encoding_auto</span></code>
is meant for automatic encoding detection. The automatic detection does not
make sense for output encoding, since there is usually nothing to infer the
actual encoding from, so here <code class="computeroutput"><span class="identifier">encoding_auto</span></code>
means UTF-8 encoding, which is the most popular encoding for XML data storage.
This is also the default value of output encoding; specify another value
if you do not want UTF-8 encoded output.
</p>
<p>
Also note that wide stream saving functions do not have <code class="computeroutput"><span class="identifier">encoding</span></code>
argument and always assume <a class="link" href="loading.html#encoding_wchar">encoding_wchar</a>
encoding.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The current behavior for Unicode conversion is to skip all invalid UTF
sequences during conversion. This behavior should not be relied upon; if
your node/attribute names do not contain any valid UTF sequences, they
may be output as if they are empty, which will result in malformed XML
document.
</p></td></tr>
</table></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <b>Saving</b> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="modify.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="xpath.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
+153
View File
@@ -0,0 +1,153 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Table of Contents</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="apiref.html" title="API Reference">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<b>Table of Contents</b>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="apiref.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.toc"></a><a class="link" href="toc.html" title="Table of Contents"> Table of Contents</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="../manual.html#manual.overview"> Overview</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="../manual.html#manual.overview.introduction"> Introduction</a></span></dt>
<dt><span class="section"><a href="../manual.html#manual.overview.feedback"> Feedback</a></span></dt>
<dt><span class="section"><a href="../manual.html#manual.overview.thanks"> Acknowledgments</a></span></dt>
<dt><span class="section"><a href="../manual.html#manual.overview.license"> License</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="install.html"> Installation</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="install.html#manual.install.getting"> Getting pugixml</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="install.html#manual.install.getting.source"> Source distributions</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.getting.subversion"> Subversion repository</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="install.html#manual.install.building"> Building pugixml</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="install.html#manual.install.building.embed"> Building pugixml as
a part of another static library/executable</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.static"> Building pugixml as
a standalone static library</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.shared"> Building pugixml as
a standalone shared library</a></span></dt>
<dt><span class="section"><a href="install.html#manual.install.building.config"> Additional configuration
options</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="install.html#manual.install.portability"> Portability</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="dom.html"> Document object model</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="dom.html#manual.dom.tree"> Tree structure</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.cpp"> C++ interface</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.unicode"> Unicode interface</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.thread"> Thread-safety guarantees</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.exception"> Exception guarantees</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.memory"> Memory management</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="dom.html#manual.dom.memory.custom"> Custom memory allocation/deallocation
functions</a></span></dt>
<dt><span class="section"><a href="dom.html#manual.dom.memory.internals"> Document memory management
internals</a></span></dt>
</dl></dd>
</dl></dd>
<dt><span class="section"><a href="loading.html"> Loading document</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="loading.html#manual.loading.file"> Loading document from file</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.memory"> Loading document from memory</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.stream"> Loading document from C++ IOstreams</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.errors"> Handling parsing errors</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.options"> Parsing options</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.encoding"> Encodings</a></span></dt>
<dt><span class="section"><a href="loading.html#manual.loading.w3c"> Conformance to W3C specification</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="access.html"> Accessing document data</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="access.html#manual.access.basic"> Basic traversal functions</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.nodedata"> Getting node data</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.attrdata"> Getting attribute data</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.contents"> Contents-based traversal functions</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.iterators"> Traversing node/attribute lists
via iterators</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.walker"> Recursive traversal with xml_tree_walker</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.predicate"> Searching for nodes/attributes
with predicates</a></span></dt>
<dt><span class="section"><a href="access.html#manual.access.misc"> Miscellaneous functions</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="modify.html"> Modifying document data</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="modify.html#manual.modify.nodedata"> Setting node data</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.attrdata"> Setting attribute data</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.add"> Adding nodes/attributes</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.remove"> Removing nodes/attributes</a></span></dt>
<dt><span class="section"><a href="modify.html#manual.modify.clone"> Cloning nodes/attributes</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="saving.html"> Saving document</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="saving.html#manual.saving.file"> Saving document to a file</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.stream"> Saving document to C++ IOstreams</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.writer"> Saving document via writer interface</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.subtree"> Saving a single subtree</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.options"> Output options</a></span></dt>
<dt><span class="section"><a href="saving.html#manual.saving.encoding"> Encodings</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="xpath.html"> XPath</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="xpath.html#manual.xpath.types"> XPath types</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.select"> Selecting nodes via XPath expression</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.query"> Using query objects</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.variables"> Using variables</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.errors"> Error handling</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.w3c"> Conformance to W3C specification</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="changes.html"> Changelog</a></span></dt>
<dt><span class="section"><a href="apiref.html"> API Reference</a></span></dt>
<dt><span class="section"><a href="toc.html"> Table of Contents</a></span></dt>
</dl></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<a href="xpath.html">XPath</a> |
<a href="apiref.html">API Reference</a> |
<b>Table of Contents</b>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="apiref.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a>
</div></td>
</tr></table>
</body>
</html>
+742
View File
@@ -0,0 +1,742 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>XPath</title>
<link rel="stylesheet" href="../pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../manual.html" title="pugixml 1.0">
<link rel="up" href="../manual.html" title="pugixml 1.0">
<link rel="prev" href="saving.html" title="Saving document">
<link rel="next" href="changes.html" title="Changelog">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<b>XPath</b> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="saving.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="changes.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
<hr>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="manual.xpath"></a><a class="link" href="xpath.html" title="XPath"> XPath</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="xpath.html#manual.xpath.types"> XPath types</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.select"> Selecting nodes via XPath expression</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.query"> Using query objects</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.variables"> Using variables</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.errors"> Error handling</a></span></dt>
<dt><span class="section"><a href="xpath.html#manual.xpath.w3c"> Conformance to W3C specification</a></span></dt>
</dl></div>
<p>
If the task at hand is to select a subset of document nodes that match some
criteria, it is possible to code a function using the existing traversal functionality
for any practical criteria. However, often either a data-driven approach is
desirable, in case the criteria are not predefined and come from a file, or
it is inconvenient to use traversal interfaces and a higher-level DSL is required.
There is a standard language for XML processing, XPath, that can be useful
for these cases. pugixml implements an almost complete subset of XPath 1.0.
Because of differences in document object model and some performance implications,
there are minor violations of the official specifications, which can be found
in <a class="xref" href="xpath.html#manual.xpath.w3c" title="Conformance to W3C specification"> Conformance to W3C specification</a>. The rest of this section describes the interface for XPath
functionality. Please note that if you wish to learn to use XPath language,
you have to look for other tutorials or manuals; for example, you can read
<a href="http://www.w3schools.com/xpath/" target="_top">W3Schools XPath tutorial</a>,
<a href="http://www.tizag.com/xmlTutorial/xpathtutorial.php" target="_top">XPath tutorial
at tizag.com</a>, and <a href="http://www.w3.org/TR/xpath/" target="_top">the XPath
1.0 specification</a>.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.types"></a><a class="link" href="xpath.html#manual.xpath.types" title="XPath types"> XPath types</a>
</h3></div></div></div>
<a name="xpath_value_type"></a><a name="xpath_type_number"></a><a name="xpath_type_string"></a><a name="xpath_type_boolean"></a><a name="xpath_type_node_set"></a><a name="xpath_type_none"></a><p>
Each XPath expression can have one of the following types: boolean, number,
string or node set. Boolean type corresponds to <code class="computeroutput"><span class="keyword">bool</span></code>
type, number type corresponds to <code class="computeroutput"><span class="keyword">double</span></code>
type, string type corresponds to either <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wstring</span></code>, depending on whether <a class="link" href="dom.html#manual.dom.unicode" title="Unicode interface">wide
character interface is enabled</a>, and node set corresponds to <a class="link" href="xpath.html#xpath_node_set">xpath_node_set</a> type. There is an enumeration,
<code class="computeroutput"><span class="identifier">xpath_value_type</span></code>, which can
take the values <code class="computeroutput"><span class="identifier">xpath_type_boolean</span></code>,
<code class="computeroutput"><span class="identifier">xpath_type_number</span></code>, <code class="computeroutput"><span class="identifier">xpath_type_string</span></code> or <code class="computeroutput"><span class="identifier">xpath_type_node_set</span></code>,
accordingly.
</p>
<a name="xpath_node"></a><a name="xpath_node::node"></a><a name="xpath_node::attribute"></a><a name="xpath_node::parent"></a><p>
Because an XPath node can be either a node or an attribute, there is a special
type, <code class="computeroutput"><span class="identifier">xpath_node</span></code>, which is
a discriminated union of these types. A value of this type contains two node
handles, one of <code class="computeroutput"><span class="identifier">xml_node</span></code>
type, and another one of <code class="computeroutput"><span class="identifier">xml_attribute</span></code>
type; at most one of them can be non-null. The accessors to get these handles
are available:
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xpath_node</span><span class="special">::</span><span class="identifier">node</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xml_attribute</span> <span class="identifier">xpath_node</span><span class="special">::</span><span class="identifier">attribute</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
XPath nodes can be null, in which case both accessors return null handles.
</p>
<p>
Note that as per XPath specification, each XPath node has a parent, which
can be retrieved via this function:
</p>
<pre class="programlisting"><span class="identifier">xml_node</span> <span class="identifier">xpath_node</span><span class="special">::</span><span class="identifier">parent</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">parent</span></code> function returns the
node's parent if the XPath node corresponds to <code class="computeroutput"><span class="identifier">xml_node</span></code>
handle (equivalent to <code class="computeroutput"><span class="identifier">node</span><span class="special">().</span><span class="identifier">parent</span><span class="special">()</span></code>), or the node to which the attribute belongs
to, if the XPath node corresponds to <code class="computeroutput"><span class="identifier">xml_attribute</span></code>
handle. For null nodes, <code class="computeroutput"><span class="identifier">parent</span></code>
returns null handle.
</p>
<a name="xpath_node::unspecified_bool_type"></a><a name="xpath_node::comparison"></a><p>
Like node and attribute handles, XPath node handles can be implicitly cast
to boolean-like object to check if it is a null node, and also can be compared
for equality with each other.
</p>
<a name="xpath_node::ctor"></a><p>
You can also create XPath nodes with one of the three constructors: the default
constructor, the constructor that takes node argument, and the constructor
that takes attribute and node arguments (in which case the attribute must
belong to the attribute list of the node). The constructor from <code class="computeroutput"><span class="identifier">xml_node</span></code> is implicit, so you can usually
pass <code class="computeroutput"><span class="identifier">xml_node</span></code> to functions
that expect <code class="computeroutput"><span class="identifier">xpath_node</span></code>. Apart
from that you usually don't need to create your own XPath node objects, since
they are returned to you via selection functions.
</p>
<a name="xpath_node_set"></a><p>
XPath expressions operate not on single nodes, but instead on node sets.
A node set is a collection of nodes, which can be optionally ordered in either
a forward document order or a reverse one. Document order is defined in XPath
specification; an XPath node is before another node in document order if
it appears before it in XML representation of the corresponding document.
</p>
<a name="xpath_node_set::const_iterator"></a><a name="xpath_node_set::begin"></a><a name="xpath_node_set::end"></a><p>
Node sets are represented by <code class="computeroutput"><span class="identifier">xpath_node_set</span></code>
object, which has an interface that resembles one of sequential random-access
containers. It has an iterator type along with usual begin/past-the-end iterator
accessors:
</p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">*</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">const_iterator</span><span class="special">;</span>
<span class="identifier">const_iterator</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">const_iterator</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<a name="xpath_node_set::index"></a><a name="xpath_node_set::size"></a><a name="xpath_node_set::empty"></a><p>
And it also can be iterated via indices, just like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span></code>:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="keyword">operator</span><span class="special">[](</span><span class="identifier">size_t</span> <span class="identifier">index</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">size_t</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">size</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">empty</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
All of the above operations have the same semantics as that of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span></code>:
the iterators are random-access, all of the above operations are constant
time, and accessing the element at index that is greater or equal than the
set size results in undefined behavior. You can use both iterator-based and
index-based access for iteration, however the iterator-based one can be faster.
</p>
<a name="xpath_node_set::type"></a><a name="xpath_node_set::type_unsorted"></a><a name="xpath_node_set::type_sorted"></a><a name="xpath_node_set::type_sorted_reverse"></a><a name="xpath_node_set::sort"></a><p>
The order of iteration depends on the order of nodes inside the set; the
order can be queried via the following function:
</p>
<pre class="programlisting"><span class="keyword">enum</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">type_t</span> <span class="special">{</span><span class="identifier">type_unsorted</span><span class="special">,</span> <span class="identifier">type_sorted</span><span class="special">,</span> <span class="identifier">type_sorted_reverse</span><span class="special">};</span>
<span class="identifier">type_t</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">type</span></code> function returns the
current order of nodes; <code class="computeroutput"><span class="identifier">type_sorted</span></code>
means that the nodes are in forward document order, <code class="computeroutput"><span class="identifier">type_sorted_reverse</span></code>
means that the nodes are in reverse document order, and <code class="computeroutput"><span class="identifier">type_unsorted</span></code>
means that neither order is guaranteed (nodes can accidentally be in a sorted
order even if <code class="computeroutput"><span class="identifier">type</span><span class="special">()</span></code>
returns <code class="computeroutput"><span class="identifier">type_unsorted</span></code>). If
you require a specific order of iteration, you can change it via <code class="computeroutput"><span class="identifier">sort</span></code> function:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">sort</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">reverse</span> <span class="special">=</span> <span class="keyword">false</span><span class="special">);</span>
</pre>
<p>
Calling <code class="computeroutput"><span class="identifier">sort</span></code> sorts the nodes
in either forward or reverse document order, depending on the argument; after
this call <code class="computeroutput"><span class="identifier">type</span><span class="special">()</span></code>
will return <code class="computeroutput"><span class="identifier">type_sorted</span></code> or
<code class="computeroutput"><span class="identifier">type_sorted_reverse</span></code>.
</p>
<a name="xpath_node_set::first"></a><p>
Often the actual iteration is not needed; instead, only the first element
in document order is required. For this, a special accessor is provided:
</p>
<pre class="programlisting"><span class="identifier">xpath_node</span> <span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">first</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
This function returns the first node in forward document order from the set,
or null node if the set is empty. Note that while the result of the node
does not depend on the order of nodes in the set (i.e. on the result of
<code class="computeroutput"><span class="identifier">type</span><span class="special">()</span></code>),
the complexity does - if the set is sorted, the complexity is constant, otherwise
it is linear in the number of elements or worse.
</p>
<a name="xpath_node_set::ctor"></a><p>
While in the majority of cases the node set is returned by XPath functions,
sometimes there is a need to manually construct a node set. For such cases,
a constructor is provided which takes an iterator range (<code class="computeroutput"><span class="identifier">const_iterator</span></code>
is a typedef for <code class="computeroutput"><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">*</span></code>), and an optional type:
</p>
<pre class="programlisting"><span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">xpath_node_set</span><span class="special">(</span><span class="identifier">const_iterator</span> <span class="identifier">begin</span><span class="special">,</span> <span class="identifier">const_iterator</span> <span class="identifier">end</span><span class="special">,</span> <span class="identifier">type_t</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">type_unsorted</span><span class="special">);</span>
</pre>
<p>
The constructor copies the specified range and sets the specified type. The
objects in the range are not checked in any way; you'll have to ensure that
the range contains no duplicates, and that the objects are sorted according
to the <code class="computeroutput"><span class="identifier">type</span></code> parameter. Otherwise
XPath operations with this set may produce unexpected results.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.select"></a><a class="link" href="xpath.html#manual.xpath.select" title="Selecting nodes via XPath expression"> Selecting nodes via XPath expression</a>
</h3></div></div></div>
<a name="xml_node::select_single_node"></a><a name="xml_node::select_nodes"></a><p>
If you want to select nodes that match some XPath expression, you can do
it with the following functions:
</p>
<pre class="programlisting"><span class="identifier">xpath_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_single_node</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xpath_node_set</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">select_nodes</span></code> function compiles
the expression and then executes it with the node as a context node, and
returns the resulting node set. <code class="computeroutput"><span class="identifier">select_single_node</span></code>
returns only the first node in document order from the result, and is equivalent
to calling <code class="computeroutput"><span class="identifier">select_nodes</span><span class="special">(</span><span class="identifier">query</span><span class="special">).</span><span class="identifier">first</span><span class="special">()</span></code>.
If the XPath expression does not match anything, or the node handle is null,
<code class="computeroutput"><span class="identifier">select_nodes</span></code> returns an empty
set, and <code class="computeroutput"><span class="identifier">select_single_node</span></code>
returns null XPath node.
</p>
<p>
If exception handling is not disabled, both functions throw <a class="link" href="xpath.html#xpath_exception">xpath_exception</a>
if the query can not be compiled or if it returns a value with type other
than node set; see <a class="xref" href="xpath.html#manual.xpath.errors" title="Error handling"> Error handling</a> for details.
</p>
<a name="xml_node::select_single_node_precomp"></a><a name="xml_node::select_nodes_precomp"></a><p>
While compiling expressions is fast, the compilation time can introduce a
significant overhead if the same expression is used many times on small subtrees.
If you're doing many similar queries, consider compiling them into query
objects (see <a class="xref" href="xpath.html#manual.xpath.query" title="Using query objects"> Using query objects</a> for further reference). Once you get a compiled
query object, you can pass it to select functions instead of an expression
string:
</p>
<pre class="programlisting"><span class="identifier">xpath_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_single_node</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_query</span><span class="special">&amp;</span> <span class="identifier">query</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xpath_node_set</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_query</span><span class="special">&amp;</span> <span class="identifier">query</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
If exception handling is not disabled, both functions throw <a class="link" href="xpath.html#xpath_exception">xpath_exception</a>
if the query returns a value with type other than node set.
</p>
<p>
This is an example of selecting nodes using XPath expressions (<a href="../samples/xpath_select.cpp" target="_top">samples/xpath_select.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tools:"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">const_iterator</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> <span class="identifier">it</span> <span class="special">!=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">it</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="special">*</span><span class="identifier">it</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span>
<span class="special">}</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node</span> <span class="identifier">build_tool</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_single_node</span><span class="special">(</span><span class="string">"//Tool[contains(Description, 'build system')]"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nBuild tool: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">build_tool</span><span class="special">.</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.query"></a><a class="link" href="xpath.html#manual.xpath.query" title="Using query objects"> Using query objects</a>
</h3></div></div></div>
<a name="xpath_query"></a><p>
When you call <code class="computeroutput"><span class="identifier">select_nodes</span></code>
with an expression string as an argument, a query object is created behind
the scenes. A query object represents a compiled XPath expression. Query
objects can be needed in the following circumstances:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
You can precompile expressions to query objects to save compilation time
if it becomes an issue;
</li>
<li class="listitem">
You can use query objects to evaluate XPath expressions which result
in booleans, numbers or strings;
</li>
<li class="listitem">
You can get the type of expression value via query object.
</li>
</ul></div>
<p>
Query objects correspond to <code class="computeroutput"><span class="identifier">xpath_query</span></code>
type. They are immutable and non-copyable: they are bound to the expression
at creation time and can not be cloned. If you want to put query objects
in a container, allocate them on heap via <code class="computeroutput"><span class="keyword">new</span></code>
operator and store pointers to <code class="computeroutput"><span class="identifier">xpath_query</span></code>
in the container.
</p>
<a name="xpath_query::ctor"></a><p>
You can create a query object with the constructor that takes XPath expression
as an argument:
</p>
<pre class="programlisting"><span class="keyword">explicit</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">xpath_query</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">);</span>
</pre>
<a name="xpath_query::return_type"></a><p>
The expression is compiled and the compiled representation is stored in the
new query object. If compilation fails, <a class="link" href="xpath.html#xpath_exception">xpath_exception</a>
is thrown if exception handling is not disabled (see <a class="xref" href="xpath.html#manual.xpath.errors" title="Error handling"> Error handling</a> for
details). After the query is created, you can query the type of the evaluation
result using the following function:
</p>
<pre class="programlisting"><span class="identifier">xpath_value_type</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">return_type</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<a name="xpath_query::evaluate_boolean"></a><a name="xpath_query::evaluate_number"></a><a name="xpath_query::evaluate_string"></a><a name="xpath_query::evaluate_node_set"></a><p>
You can evaluate the query using one of the following functions:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">evaluate_boolean</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">double</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">evaluate_number</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">string_t</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">evaluate_string</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xpath_node_set</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">evaluate_node_set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
All functions take the context node as an argument, compute the expression
and return the result, converted to the requested type. According to XPath
specification, value of any type can be converted to boolean, number or string
value, but no type other than node set can be converted to node set. Because
of this, <code class="computeroutput"><span class="identifier">evaluate_boolean</span></code>,
<code class="computeroutput"><span class="identifier">evaluate_number</span></code> and <code class="computeroutput"><span class="identifier">evaluate_string</span></code> always return a result,
but <code class="computeroutput"><span class="identifier">evaluate_node_set</span></code> results
in an error if the return type is not node set (see <a class="xref" href="xpath.html#manual.xpath.errors" title="Error handling"> Error handling</a>).
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Calling <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"query"</span><span class="special">)</span></code>
is equivalent to calling <code class="computeroutput"><span class="identifier">xpath_query</span><span class="special">(</span><span class="string">"query"</span><span class="special">).</span><span class="identifier">evaluate_node_set</span><span class="special">(</span><span class="identifier">node</span><span class="special">)</span></code>.
</p></td></tr>
</table></div>
<a name="xpath_query::evaluate_string_buffer"></a><p>
Note that <code class="computeroutput"><span class="identifier">evaluate_string</span></code>
function returns the STL string; as such, it's not available in <a class="link" href="install.html#PUGIXML_NO_STL">PUGIXML_NO_STL</a>
mode and also usually allocates memory. There is another string evaluation
function:
</p>
<pre class="programlisting"><span class="identifier">size_t</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">evaluate_string</span><span class="special">(</span><span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">capacity</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xpath_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
This function evaluates the string, and then writes the result to <code class="computeroutput"><span class="identifier">buffer</span></code> (but at most <code class="computeroutput"><span class="identifier">capacity</span></code>
characters); then it returns the full size of the result in characters, including
the terminating zero. If <code class="computeroutput"><span class="identifier">capacity</span></code>
is not 0, the resulting buffer is always zero-terminated. You can use this
function as follows:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
First call the function with <code class="computeroutput"><span class="identifier">buffer</span>
<span class="special">=</span> <span class="number">0</span></code>
and <code class="computeroutput"><span class="identifier">capacity</span> <span class="special">=</span>
<span class="number">0</span></code>; then allocate the returned amount
of characters, and call the function again, passing the allocated storage
and the amount of characters;
</li>
<li class="listitem">
First call the function with small buffer and buffer capacity; then,
if the result is larger than the capacity, the output has been trimmed,
so allocate a larger buffer and call the function again.
</li>
</ul></div>
<p>
This is an example of using query objects (<a href="../samples/xpath_query.cpp" target="_top">samples/xpath_query.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Select nodes via compiled query
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_query</span> <span class="identifier">query_remote_tools</span><span class="special">(</span><span class="string">"/Profile/Tools/Tool[@AllowRemote='true']"</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools</span> <span class="special">=</span> <span class="identifier">query_remote_tools</span><span class="special">.</span><span class="identifier">evaluate_node_set</span><span class="special">(</span><span class="identifier">doc</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Remote tool: "</span><span class="special">;</span>
<span class="identifier">tools</span><span class="special">[</span><span class="number">2</span><span class="special">].</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
<span class="comment">// Evaluate numbers via compiled query
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_query</span> <span class="identifier">query_timeouts</span><span class="special">(</span><span class="string">"sum(//Tool/@Timeout)"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">query_timeouts</span><span class="special">.</span><span class="identifier">evaluate_number</span><span class="special">(</span><span class="identifier">doc</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// Evaluate strings via compiled query for different context nodes
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_query</span> <span class="identifier">query_name_valid</span><span class="special">(</span><span class="string">"string-length(substring-before(@Filename, '_')) &gt; 0 and @OutputFileMasks"</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_query</span> <span class="identifier">query_name</span><span class="special">(</span><span class="string">"concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)"</span><span class="special">);</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">first_element_by_path</span><span class="special">(</span><span class="string">"Profile/Tools/Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">())</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span> <span class="special">=</span> <span class="identifier">query_name</span><span class="special">.</span><span class="identifier">evaluate_string</span><span class="special">(</span><span class="identifier">tool</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">query_name_valid</span><span class="special">.</span><span class="identifier">evaluate_boolean</span><span class="special">(</span><span class="identifier">tool</span><span class="special">))</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">s</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.variables"></a><a class="link" href="xpath.html#manual.xpath.variables" title="Using variables"> Using variables</a>
</h3></div></div></div>
<p>
XPath queries may contain references to variables; this is useful if you
want to use queries that depend on some dynamic parameter without manually
preparing the complete query string, or if you want to reuse the same query
object for similar queries.
</p>
<p>
Variable references have the form <code class="computeroutput"><span class="identifier">$name</span></code>; in order to use them, you have to provide
a variable set, which includes all variables present in the query with correct
types. This set is passed to <code class="computeroutput"><span class="identifier">xpath_query</span></code>
constructor or to <code class="computeroutput"><span class="identifier">select_nodes</span></code>/<code class="computeroutput"><span class="identifier">select_single_node</span></code> functions:
</p>
<pre class="programlisting"><span class="keyword">explicit</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">xpath_query</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">);</span>
<span class="identifier">xpath_node</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_single_node</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xpath_node_set</span> <span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">query</span><span class="special">,</span> <span class="identifier">xpath_variable_set</span><span class="special">*</span> <span class="identifier">variables</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
If you're using query objects, you can change the variable values before
<code class="computeroutput"><span class="identifier">evaluate</span></code>/<code class="computeroutput"><span class="identifier">select</span></code>
calls to change the query behavior.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
The variable set pointer is stored in the query object; you have to ensure
that the lifetime of the set exceeds that of query object.
</p></td></tr>
</table></div>
<a name="xpath_variable_set"></a><p>
Variable sets correspond to <code class="computeroutput"><span class="identifier">xpath_variable_set</span></code>
type, which is essentially a variable container.
</p>
<a name="xpath_variable_set::add"></a><p>
You can add new variables with the following function:
</p>
<pre class="programlisting"><span class="identifier">xpath_variable</span><span class="special">*</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">add</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">xpath_value_type</span> <span class="identifier">type</span><span class="special">);</span>
</pre>
<p>
The function tries to add a new variable with the specified name and type;
if the variable with such name does not exist in the set, the function adds
a new variable and returns the variable handle; if there is already a variable
with the specified name, the function returns the variable handle if variable
has the specified type. Otherwise the function returns null pointer; it also
returns null pointer on allocation failure.
</p>
<p>
New variables are assigned the default value which depends on the type:
<code class="computeroutput"><span class="number">0</span></code> for numbers, <code class="computeroutput"><span class="keyword">false</span></code> for booleans, empty string for strings
and empty set for node sets.
</p>
<a name="xpath_variable_set::get"></a><p>
You can get the existing variables with the following functions:
</p>
<pre class="programlisting"><span class="identifier">xpath_variable</span><span class="special">*</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">get</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">);</span>
<span class="keyword">const</span> <span class="identifier">xpath_variable</span><span class="special">*</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">get</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
The functions return the variable handle, or null pointer if the variable
with the specified name is not found.
</p>
<a name="xpath_variable_set::set"></a><p>
Additionally, there are the helper functions for setting the variable value
by name; they try to add the variable with the corresponding type, if it
does not exist, and to set the value. If the variable with the same name
but with different type is already present, they return <code class="computeroutput"><span class="keyword">false</span></code>;
they also return <code class="computeroutput"><span class="keyword">false</span></code> on allocation
failure. Note that these functions do not perform any type conversions.
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">bool</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable_set</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">name</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">xpath_node_set</span><span class="special">&amp;</span> <span class="identifier">value</span><span class="special">);</span>
</pre>
<p>
The variable values are copied to the internal variable storage, so you can
modify or destroy them after the functions return.
</p>
<a name="xpath_variable"></a><p>
If setting variables by name is not efficient enough, or if you have to inspect
variable information or get variable values, you can use variable handles.
A variable corresponds to the <code class="computeroutput"><span class="identifier">xpath_variable</span></code>
type, and a variable handle is simply a pointer to <code class="computeroutput"><span class="identifier">xpath_variable</span></code>.
</p>
<a name="xpath_variable::type"></a><a name="xpath_variable::name"></a><p>
In order to get variable information, you can use one of the following functions:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">name</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="identifier">xpath_value_type</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">type</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
Note that each variable has a distinct type which is specified upon variable
creation and can not be changed later.
</p>
<a name="xpath_variable::get_boolean"></a><a name="xpath_variable::get_number"></a><a name="xpath_variable::get_string"></a><a name="xpath_variable::get_node_set"></a><p>
In order to get variable value, you should use one of the following functions,
depending on the variable type:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">get_boolean</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">double</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">get_number</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">get_string</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">xpath_node_set</span><span class="special">&amp;</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">get_node_set</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
These functions return the value of the variable. Note that no type conversions
are performed; if the type mismatch occurs, a dummy value is returned (<code class="computeroutput"><span class="keyword">false</span></code> for booleans, <code class="computeroutput"><span class="identifier">NaN</span></code>
for numbers, empty string for strings and empty set for node sets).
</p>
<a name="xpath_variable::set"></a><p>
In order to set variable value, you should use one of the following functions,
depending on the variable type:
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">char_t</span><span class="special">*</span> <span class="identifier">value</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">xpath_variable</span><span class="special">::</span><span class="identifier">set</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xpath_node_set</span><span class="special">&amp;</span> <span class="identifier">value</span><span class="special">);</span>
</pre>
<p>
These functions modify the variable value. Note that no type conversions
are performed; if the type mismatch occurs, the functions return <code class="computeroutput"><span class="keyword">false</span></code>; they also return <code class="computeroutput"><span class="keyword">false</span></code>
on allocation failure. The variable values are copied to the internal variable
storage, so you can modify or destroy them after the functions return.
</p>
<p>
This is an example of using variables in XPath queries (<a href="../samples/xpath_variables.cpp" target="_top">samples/xpath_variables.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Select nodes via compiled query
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_variable_set</span> <span class="identifier">vars</span><span class="special">;</span>
<span class="identifier">vars</span><span class="special">.</span><span class="identifier">add</span><span class="special">(</span><span class="string">"remote"</span><span class="special">,</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_type_boolean</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_query</span> <span class="identifier">query_remote_tools</span><span class="special">(</span><span class="string">"/Profile/Tools/Tool[@AllowRemote = string($remote)]"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">vars</span><span class="special">);</span>
<span class="identifier">vars</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">"remote"</span><span class="special">,</span> <span class="keyword">true</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools_remote</span> <span class="special">=</span> <span class="identifier">query_remote_tools</span><span class="special">.</span><span class="identifier">evaluate_node_set</span><span class="special">(</span><span class="identifier">doc</span><span class="special">);</span>
<span class="identifier">vars</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">"remote"</span><span class="special">,</span> <span class="keyword">false</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools_local</span> <span class="special">=</span> <span class="identifier">query_remote_tools</span><span class="special">.</span><span class="identifier">evaluate_node_set</span><span class="special">(</span><span class="identifier">doc</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Remote tool: "</span><span class="special">;</span>
<span class="identifier">tools_remote</span><span class="special">[</span><span class="number">2</span><span class="special">].</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Local tool: "</span><span class="special">;</span>
<span class="identifier">tools_local</span><span class="special">[</span><span class="number">0</span><span class="special">].</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
<span class="comment">// You can pass the context directly to select_nodes/select_single_node
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools_local_imm</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"/Profile/Tools/Tool[@AllowRemote = string($remote)]"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">vars</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Local tool imm: "</span><span class="special">;</span>
<span class="identifier">tools_local_imm</span><span class="special">[</span><span class="number">0</span><span class="special">].</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">print</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.errors"></a><a class="link" href="xpath.html#manual.xpath.errors" title="Error handling"> Error handling</a>
</h3></div></div></div>
<p>
There are two different mechanisms for error handling in XPath implementation;
the mechanism used depends on whether exception support is disabled (this
is controlled with <a class="link" href="install.html#PUGIXML_NO_EXCEPTIONS">PUGIXML_NO_EXCEPTIONS</a>
define).
</p>
<a name="xpath_exception"></a><a name="xpath_exception::result"></a><a name="xpath_exception::what"></a><p>
By default, XPath functions throw <code class="computeroutput"><span class="identifier">xpath_exception</span></code>
object in case of errors; additionally, in the event any memory allocation
fails, an <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bad_alloc</span></code> exception is thrown. Also <code class="computeroutput"><span class="identifier">xpath_exception</span></code> is thrown if the query
is evaluated to a node set, but the return type is not node set. If the query
constructor succeeds (i.e. no exception is thrown), the query object is valid.
Otherwise you can get the error details via one of the following functions:
</p>
<pre class="programlisting"><span class="keyword">virtual</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">xpath_exception</span><span class="special">::</span><span class="identifier">what</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">throw</span><span class="special">();</span>
<span class="keyword">const</span> <span class="identifier">xpath_parse_result</span><span class="special">&amp;</span> <span class="identifier">xpath_exception</span><span class="special">::</span><span class="identifier">result</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<a name="xpath_query::unspecified_bool_type"></a><a name="xpath_query::result"></a><p>
If exceptions are disabled, then in the event of parsing failure the query
is initialized to invalid state; you can test if the query object is valid
by using it in a boolean expression: <code class="computeroutput"><span class="keyword">if</span>
<span class="special">(</span><span class="identifier">query</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span>
<span class="special">}</span></code>. Additionally, you can get parsing
result via the result() accessor:
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="identifier">xpath_parse_result</span><span class="special">&amp;</span> <span class="identifier">xpath_query</span><span class="special">::</span><span class="identifier">result</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
</pre>
<p>
Without exceptions, evaluating invalid query results in <code class="computeroutput"><span class="keyword">false</span></code>,
empty string, NaN or an empty node set, depending on the type; evaluating
a query as a node set results in an empty node set if the return type is
not node set.
</p>
<a name="xpath_parse_result"></a><p>
The information about parsing result is returned via <code class="computeroutput"><span class="identifier">xpath_parse_result</span></code>
object. It contains parsing status and the offset of last successfully parsed
character from the beginning of the source stream:
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">xpath_parse_result</span>
<span class="special">{</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">error</span><span class="special">;</span>
<span class="identifier">ptrdiff_t</span> <span class="identifier">offset</span><span class="special">;</span>
<span class="keyword">operator</span> <span class="keyword">bool</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">description</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<a name="xpath_parse_result::error"></a><p>
Parsing result is represented as the error message; it is either a null pointer,
in case there is no error, or the error message in the form of ASCII zero-terminated
string.
</p>
<a name="xpath_parse_result::description"></a><p>
<code class="computeroutput"><span class="identifier">description</span><span class="special">()</span></code>
member function can be used to get the error message; it never returns the
null pointer, so you can safely use description() even if query parsing succeeded.
</p>
<a name="xpath_parse_result::offset"></a><p>
In addition to the error message, parsing result has an <code class="computeroutput"><span class="identifier">offset</span></code>
member, which contains the offset of last successfully parsed character.
This offset is in units of <a class="link" href="dom.html#char_t">pugi::char_t</a> (bytes
for character mode, wide characters for wide character mode).
</p>
<a name="xpath_parse_result::bool"></a><p>
Parsing result object can be implicitly converted to <code class="computeroutput"><span class="keyword">bool</span></code>
like this: <code class="computeroutput"><span class="keyword">if</span> <span class="special">(</span><span class="identifier">result</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span>
<span class="keyword">else</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>.
</p>
<p>
This is an example of XPath error handling (<a href="../samples/xpath_error.cpp" target="_top">samples/xpath_error.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Exception is thrown for incorrect query syntax
</span><span class="keyword">try</span>
<span class="special">{</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"//nodes[#true()]"</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="keyword">const</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_exception</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Select failed: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// Exception is thrown for incorrect query semantics
</span><span class="keyword">try</span>
<span class="special">{</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"(123)/next"</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="keyword">const</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_exception</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Select failed: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// Exception is thrown for query with incorrect return type
</span><span class="keyword">try</span>
<span class="special">{</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"123"</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="keyword">const</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_exception</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Select failed: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="manual.xpath.w3c"></a><a class="link" href="xpath.html#manual.xpath.w3c" title="Conformance to W3C specification"> Conformance to W3C specification</a>
</h3></div></div></div>
<p>
Because of the differences in document object models, performance considerations
and implementation complexity, pugixml does not provide a fully conformant
XPath 1.0 implementation. This is the current list of incompatibilities:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Consecutive text nodes sharing the same parent are not merged, i.e. in
<code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span><span class="identifier">text1</span>
<span class="special">&lt;![</span><span class="identifier">CDATA</span><span class="special">[</span><span class="identifier">data</span><span class="special">]]&gt;</span> <span class="identifier">text2</span><span class="special">&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span></code> node should have one text node children,
but instead has three.
</li>
<li class="listitem">
Since the document type declaration is not used for parsing, <code class="computeroutput"><span class="identifier">id</span><span class="special">()</span></code>
function always returns an empty node set.
</li>
<li class="listitem">
Namespace nodes are not supported (affects namespace:: axis).
</li>
<li class="listitem">
Name tests are performed on QNames in XML document instead of expanded
names; for <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">foo</span>
<span class="identifier">xmlns</span><span class="special">:</span><span class="identifier">ns1</span><span class="special">=</span><span class="char">'uri'</span> <span class="identifier">xmlns</span><span class="special">:</span><span class="identifier">ns2</span><span class="special">=</span><span class="char">'uri'</span><span class="special">&gt;&lt;</span><span class="identifier">ns1</span><span class="special">:</span><span class="identifier">child</span><span class="special">/&gt;&lt;</span><span class="identifier">ns2</span><span class="special">:</span><span class="identifier">child</span><span class="special">/&gt;&lt;/</span><span class="identifier">foo</span><span class="special">&gt;</span></code>,
query <code class="computeroutput"><span class="identifier">foo</span><span class="special">/</span><span class="identifier">ns1</span><span class="special">:*</span></code>
will return only the first child, not both of them. Compliant XPath implementations
can return both nodes if the user provides appropriate namespace declarations.
</li>
<li class="listitem">
String functions consider a character to be either a single <code class="computeroutput"><span class="keyword">char</span></code> value or a single <code class="computeroutput"><span class="keyword">wchar_t</span></code>
value, depending on the library configuration; this means that some string
functions are not fully Unicode-aware. This affects <code class="computeroutput"><span class="identifier">substring</span><span class="special">()</span></code>, <code class="computeroutput"><span class="identifier">string</span><span class="special">-</span><span class="identifier">length</span><span class="special">()</span></code> and <code class="computeroutput"><span class="identifier">translate</span><span class="special">()</span></code> functions.
</li>
</ul></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2010 Arseny Kapoulkine<p>
Distributed under the MIT License
</p>
</div></td>
</tr></table>
<hr>
<table width="100%"><tr>
<td>
<a href="http://pugixml.org/">pugixml 1.0</a> manual |
<a href="../manual.html">Overview</a> |
<a href="install.html">Installation</a> |
Document:
<a href="dom.html">Object model</a> &middot; <a href="loading.html">Loading</a> &middot; <a href="access.html">Accessing</a> &middot; <a href="modify.html">Modifying</a> &middot; <a href="saving.html">Saving</a> |
<b>XPath</b> |
<a href="apiref.html">API Reference</a> |
<a href="toc.html">Table of Contents</a>
</td>
<td width="*" align="right"><div class="spirit-nav">
<a accesskey="p" href="saving.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../manual.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../manual.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="changes.html"><img src="../images/next.png" alt="Next"></a>
</div></td>
</tr></table>
</body>
</html>
+598
View File
@@ -0,0 +1,598 @@
/*=============================================================================
Copyright (c) 2004 Joel de Guzman
http://spirit.sourceforge.net/
Distributed under the Boost Software License, Version 1.0. (See accompany-
ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
/*=============================================================================
Body defaults
=============================================================================*/
body
{
margin: 1em;
font-family: sans-serif;
}
/*=============================================================================
Paragraphs
=============================================================================*/
p
{
text-align: left;
font-size: 10pt;
line-height: 1.15;
}
/*=============================================================================
Program listings
=============================================================================*/
/* Code on paragraphs */
p tt.computeroutput
{
font-size: 9pt;
}
pre.synopsis
{
font-size: 90%;
margin: 1pc 4% 0pc 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
.programlisting,
.screen
{
font-size: 9pt;
display: block;
margin: 1pc 4% 0pc 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
/* Program listings in tables don't get borders */
td .programlisting,
td .screen
{
margin: 0pc 0pc 0pc 0pc;
padding: 0pc 0pc 0pc 0pc;
}
/*=============================================================================
Headings
=============================================================================*/
h1, h2, h3, h4, h5, h6
{
text-align: left;
margin: 1em 0em 0.5em 0em;
font-weight: bold;
}
h1 { font: 140% }
h2 { font: bold 140% }
h3 { font: bold 130% }
h4 { font: bold 120% }
h5 { font: italic 110% }
h6 { font: italic 100% }
/* Top page titles */
title,
h1.title,
h2.title
h3.title,
h4.title,
h5.title,
h6.title,
.refentrytitle
{
font-weight: bold;
margin-bottom: 1pc;
}
h1.title { font-size: 140% }
h2.title { font-size: 140% }
h3.title { font-size: 130% }
h4.title { font-size: 120% }
h5.title { font-size: 110% }
h6.title { font-size: 100% }
.section h1
{
margin: 0em 0em 0.5em 0em;
font-size: 140%;
}
.section h2 { font-size: 140% }
.section h3 { font-size: 130% }
.section h4 { font-size: 120% }
.section h5 { font-size: 110% }
.section h6 { font-size: 100% }
/* Code on titles */
h1 tt.computeroutput { font-size: 140% }
h2 tt.computeroutput { font-size: 140% }
h3 tt.computeroutput { font-size: 130% }
h4 tt.computeroutput { font-size: 130% }
h5 tt.computeroutput { font-size: 130% }
h6 tt.computeroutput { font-size: 130% }
/*=============================================================================
Author
=============================================================================*/
h3.author
{
font-size: 100%
}
/*=============================================================================
Lists
=============================================================================*/
li
{
font-size: 10pt;
line-height: 1.3;
}
/* Unordered lists */
ul
{
text-align: left;
}
/* Ordered lists */
ol
{
text-align: left;
}
/*=============================================================================
Links
=============================================================================*/
a
{
text-decoration: none; /* no underline */
}
a:hover
{
text-decoration: underline;
}
/*=============================================================================
Spirit style navigation
=============================================================================*/
.spirit-nav
{
text-align: right;
}
.spirit-nav a
{
color: white;
padding-left: 0.5em;
}
.spirit-nav img
{
border-width: 0px;
}
/*=============================================================================
Copyright footer
=============================================================================*/
.copyright-footer
{
text-align: right;
font-size: 70%;
}
.copyright-footer p
{
text-align: right;
font-size: 80%;
}
/*=============================================================================
Table of contents
=============================================================================*/
.toc
{
margin: 1pc 4% 0pc 4%;
padding: 0.1pc 1pc 0.1pc 1pc;
font-size: 80%;
line-height: 1.15;
}
.boost-toc
{
float: right;
padding: 0.5pc;
}
/* Code on toc */
.toc .computeroutput { font-size: 120% }
/*=============================================================================
Tables
=============================================================================*/
.table-title,
div.table p.title
{
margin-left: 4%;
padding-right: 0.5em;
padding-left: 0.5em;
}
.informaltable table,
.table table
{
width: 92%;
margin-left: 4%;
margin-right: 4%;
}
div.informaltable table,
div.table table
{
padding: 4px;
}
/* Table Cells */
div.informaltable table tr td,
div.table table tr td
{
padding: 0.5em;
text-align: left;
font-size: 9pt;
}
div.informaltable table tr th,
div.table table tr th
{
padding: 0.5em 0.5em 0.5em 0.5em;
border: 1pt solid white;
font-size: 80%;
}
table.simplelist
{
width: auto !important;
margin: 0em !important;
padding: 0em !important;
border: none !important;
}
table.simplelist td
{
margin: 0em !important;
padding: 0em !important;
text-align: left !important;
font-size: 9pt !important;
border: none !important;
}
/*=============================================================================
Blurbs
=============================================================================*/
div.note,
div.tip,
div.important,
div.caution,
div.warning,
p.blurb
{
font-size: 9pt; /* A little bit smaller than the main text */
line-height: 1.2;
display: block;
margin: 1pc 4% 0pc 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
p.blurb img
{
padding: 1pt;
}
/*=============================================================================
Variable Lists
=============================================================================*/
div.variablelist
{
margin: 1em 0;
}
/* Make the terms in definition lists bold */
div.variablelist dl dt,
span.term
{
font-weight: bold;
font-size: 10pt;
}
div.variablelist table tbody tr td
{
text-align: left;
vertical-align: top;
padding: 0em 2em 0em 0em;
font-size: 10pt;
margin: 0em 0em 0.5em 0em;
line-height: 1;
}
div.variablelist dl dt
{
margin-bottom: 0.2em;
}
div.variablelist dl dd
{
margin: 0em 0em 0.5em 2em;
font-size: 10pt;
}
div.variablelist table tbody tr td p,
div.variablelist dl dd p
{
margin: 0em 0em 0.5em 0em;
line-height: 1;
}
/*=============================================================================
Misc
=============================================================================*/
/* Title of books and articles in bibliographies */
span.title
{
font-style: italic;
}
span.underline
{
text-decoration: underline;
}
span.strikethrough
{
text-decoration: line-through;
}
/* Copyright, Legal Notice */
div div.legalnotice p
{
text-align: left
}
/*=============================================================================
Colors
=============================================================================*/
@media screen
{
body {
background-color: #FFFFFF;
color: #000000;
}
/* Links */
a
{
color: #005a9c;
}
a:visited
{
color: #9c5a9c;
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a,
h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover,
h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited
{
text-decoration: none; /* no underline */
color: #000000;
}
/* Syntax Highlighting */
.keyword { color: #0000AA; }
.identifier { color: #000000; }
.special { color: #707070; }
.preprocessor { color: #402080; }
.char { color: teal; }
.comment { color: #800000; }
.string { color: teal; }
.number { color: teal; }
.white_bkd { background-color: #FFFFFF; }
.dk_grey_bkd { background-color: #999999; }
/* Copyright, Legal Notice */
.copyright
{
color: #666666;
font-size: small;
}
div div.legalnotice p
{
color: #666666;
}
/* Program listing */
pre.synopsis
{
border: 1px solid #DCDCDC;
}
.programlisting,
.screen
{
border: 1px solid #DCDCDC;
}
td .programlisting,
td .screen
{
border: 0px solid #DCDCDC;
}
/* Blurbs */
div.note,
div.tip,
div.important,
div.caution,
div.warning,
p.blurb
{
border: 1px solid #DCDCDC;
}
/* Table of contents */
.toc
{
border: 1px solid #DCDCDC;
}
/* Tables */
div.informaltable table tr td,
div.table table tr td
{
border: 1px solid #DCDCDC;
}
div.informaltable table tr th,
div.table table tr th
{
background-color: #F0F0F0;
border: 1px solid #DCDCDC;
}
.copyright-footer
{
color: #8F8F8F;
}
/* Misc */
span.highlight
{
color: #00A000;
}
}
@media print
{
/* Links */
a
{
color: black;
}
a:visited
{
color: black;
}
.spirit-nav
{
display: none;
}
/* Program listing */
pre.synopsis
{
border: 1px solid gray;
}
.programlisting,
.screen
{
border: 1px solid gray;
}
td .programlisting,
td .screen
{
border: 0px solid #DCDCDC;
}
/* Table of contents */
.toc
{
border: 1px solid gray;
}
.informaltable table,
.table table
{
border: 1px solid gray;
border-collapse: collapse;
}
/* Tables */
div.informaltable table tr td,
div.table table tr td
{
border: 1px solid gray;
}
div.informaltable table tr th,
div.table table tr th
{
border: 1px solid gray;
}
table.simplelist tr td
{
border: none !important;
}
/* Misc */
span.highlight
{
font-weight: bold;
}
}
/*=============================================================================
Images
=============================================================================*/
span.inlinemediaobject img
{
vertical-align: middle;
}
/*==============================================================================
Super and Subscript: style so that line spacing isn't effected, see
http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341
==============================================================================*/
sup,
sub {
height: 0;
line-height: 1;
vertical-align: baseline;
_vertical-align: bottom;
position: relative;
}
sup {
bottom: 1ex;
}
sub {
top: .5ex;
}
+845
View File
@@ -0,0 +1,845 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>pugixml 1.0</title>
<link rel="stylesheet" href="pugixml.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="quickstart.html" title="pugixml 1.0">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="article">
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="quickstart.main"></a><a class="link" href="quickstart.html#quickstart.main" title="pugixml 1.0 quick start guide"> pugixml 1.0 quick start guide</a>
</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section"><a href="quickstart.html#quickstart.main.introduction"> Introduction</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.install"> Installation</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.dom"> Document object model</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.loading"> Loading document</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.access"> Accessing document data</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.modify"> Modifying document data</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.saving"> Saving document</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.feedback"> Feedback</a></span></dt>
<dt><span class="section"><a href="quickstart.html#quickstart.main.license"> License</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.introduction"></a><a class="link" href="quickstart.html#quickstart.main.introduction" title="Introduction"> Introduction</a>
</h3></div></div></div>
<p>
<a href="http://pugixml.org/" target="_top">pugixml</a> is a light-weight C++ XML
processing library. It consists of a DOM-like interface with rich traversal/modification
capabilities, an extremely fast XML parser which constructs the DOM tree
from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven
tree queries. Full Unicode support is also available, with Unicode interface
variants and conversions between different Unicode encodings (which happen
automatically during parsing/saving). The library is extremely portable and
easy to integrate and use. pugixml is developed and maintained since 2006
and has many users. All code is distributed under the <a class="link" href="quickstart.html#quickstart.main.license" title="License">MIT
license</a>, making it completely free to use in both open-source and
proprietary applications.
</p>
<p>
pugixml enables very fast, convenient and memory-efficient XML document processing.
However, since pugixml has a DOM parser, it can't process XML documents that
do not fit in memory; also the parser is a non-validating one, so if you
need DTD/Schema validation, the library is not for you.
</p>
<p>
This is the quick start guide for pugixml, which purpose is to enable you
to start using the library quickly. Many important library features are either
not described at all or only mentioned briefly; for more complete information
you <a href="manual.html" target="_top">should read the complete manual</a>.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
No documentation is perfect, neither is this one. If you encounter a description
that is unclear, please file an issue as described in <a class="xref" href="quickstart.html#quickstart.main.feedback" title="Feedback"> Feedback</a>. Also if
you can spare the time for a full proof-reading, including spelling and
grammar, that would be great! Please <a class="link" href="quickstart.html#email">send me an e-mail</a>;
as a token of appreciation, your name will be included into the corresponding
section of the manual.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.install"></a><a class="link" href="quickstart.html#quickstart.main.install" title="Installation"> Installation</a>
</h3></div></div></div>
<p>
pugixml is distributed in source form. You can download a source distribution
via one of the following links:
</p>
<pre class="programlisting"><a href="http://pugixml.googlecode.com/files/pugixml-1.0.zip" target="_top">http://pugixml.googlecode.com/files/pugixml-1.0.zip</a>
<a href="http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz" target="_top">http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz</a>
</pre>
<p>
The distribution contains library source, documentation (the guide you're
reading now and the manual) and some code examples. After downloading the
distribution, install pugixml by extracting all files from the compressed
archive. The files have different line endings depending on the archive format
- <code class="filename">.zip</code> archive has Windows line endings, <code class="filename">.tar.gz</code> archive has Unix line endings.
Otherwise the files in both archives are identical.
</p>
<p>
The complete pugixml source consists of three files - one source file, <code class="filename">pugixml.cpp</code>,
and two header files, <code class="filename">pugixml.hpp</code> and <code class="filename">pugiconfig.hpp</code>. <code class="filename">pugixml.hpp</code> is the primary
header which you need to include in order to use pugixml classes/functions.
The rest of this guide assumes that <code class="filename">pugixml.hpp</code> is either in the current directory
or in one of include directories of your projects, so that <code class="computeroutput"><span class="preprocessor">#include</span> <span class="string">"pugixml.hpp"</span></code>
can find the header; however you can also use relative path (i.e. <code class="computeroutput"><span class="preprocessor">#include</span> <span class="string">"../libs/pugixml/src/pugixml.hpp"</span></code>)
or include directory-relative path (i.e. <code class="computeroutput"><span class="preprocessor">#include</span>
<span class="special">&lt;</span><span class="identifier">xml</span><span class="special">/</span><span class="identifier">thirdparty</span><span class="special">/</span><span class="identifier">pugixml</span><span class="special">/</span><span class="identifier">src</span><span class="special">/</span><span class="identifier">pugixml</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code>).
</p>
<p>
The easiest way to build pugixml is to compile the source file, <code class="filename">pugixml.cpp</code>,
along with the existing library/executable. This process depends on the method
of building your application; for example, if you're using Microsoft Visual
Studio<sup>[<a name="trademarks" href="#ftn.trademarks" class="footnote">1</a>]</sup>,
Apple Xcode, Code::Blocks or any other IDE, just add <code class="filename">pugixml.cpp</code> to one of
your projects. There are other building methods available, including building
pugixml as a standalone static/shared library; <a href="manual/install.html#manual.install.building" target="_top">read
the manual</a> for further information.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.dom"></a><a class="link" href="quickstart.html#quickstart.main.dom" title="Document object model"> Document object model</a>
</h3></div></div></div>
<p>
pugixml stores XML data in DOM-like way: the entire XML document (both document
structure and element data) is stored in memory as a tree. The tree can be
loaded from character stream (file, string, C++ I/O stream), then traversed
via special API or XPath expressions. The whole tree is mutable: both node
structure and node/attribute data can be changed at any time. Finally, the
result of document transformations can be saved to a character stream (file,
C++ I/O stream or custom transport).
</p>
<p>
The root of the tree is the document itself, which corresponds to C++ type
<code class="computeroutput"><span class="identifier">xml_document</span></code>. Document has
one or more child nodes, which correspond to C++ type <code class="computeroutput"><span class="identifier">xml_node</span></code>.
Nodes have different types; depending on a type, a node can have a collection
of child nodes, a collection of attributes, which correspond to C++ type
<code class="computeroutput"><span class="identifier">xml_attribute</span></code>, and some additional
data (i.e. name).
</p>
<p>
The most common node types are:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
Document node (<code class="computeroutput"><span class="identifier">node_document</span></code>)
- this is the root of the tree, which consists of several child nodes.
This node corresponds to <code class="computeroutput"><span class="identifier">xml_document</span></code>
class; note that <code class="computeroutput"><span class="identifier">xml_document</span></code>
is a sub-class of <code class="computeroutput"><span class="identifier">xml_node</span></code>,
so the entire node interface is also available.
</li>
<li class="listitem">
Element/tag node (<code class="computeroutput"><span class="identifier">node_element</span></code>)
- this is the most common type of node, which represents XML elements.
Element nodes have a name, a collection of attributes and a collection
of child nodes (both of which may be empty). The attribute is a simple
name/value pair.
</li>
<li class="listitem">
Plain character data nodes (<code class="computeroutput"><span class="identifier">node_pcdata</span></code>)
represent plain text in XML. PCDATA nodes have a value, but do not have
name or children/attributes. Note that plain character data is not a
part of the element node but instead has its own node; for example, an
element node can have several child PCDATA nodes.
</li>
</ul></div>
<p>
Despite the fact that there are several node types, there are only three
C++ types representing the tree (<code class="computeroutput"><span class="identifier">xml_document</span></code>,
<code class="computeroutput"><span class="identifier">xml_node</span></code>, <code class="computeroutput"><span class="identifier">xml_attribute</span></code>);
some operations on <code class="computeroutput"><span class="identifier">xml_node</span></code>
are only valid for certain node types. They are described below.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
All pugixml classes and functions are located in <code class="computeroutput"><span class="identifier">pugi</span></code>
namespace; you have to either use explicit name qualification (i.e. <code class="computeroutput"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span></code>), or to gain access to relevant
symbols via <code class="computeroutput"><span class="keyword">using</span></code> directive
(i.e. <code class="computeroutput"><span class="keyword">using</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">;</span></code> or <code class="computeroutput"><span class="keyword">using</span>
<span class="keyword">namespace</span> <span class="identifier">pugi</span><span class="special">;</span></code>).
</p></td></tr>
</table></div>
<p>
<code class="computeroutput"><span class="identifier">xml_document</span></code> is the owner
of the entire document structure; destroying the document destroys the whole
tree. The interface of <code class="computeroutput"><span class="identifier">xml_document</span></code>
consists of loading functions, saving functions and the entire interface
of <code class="computeroutput"><span class="identifier">xml_node</span></code>, which allows
for document inspection and/or modification. Note that while <code class="computeroutput"><span class="identifier">xml_document</span></code> is a sub-class of <code class="computeroutput"><span class="identifier">xml_node</span></code>, <code class="computeroutput"><span class="identifier">xml_node</span></code>
is not a polymorphic type; the inheritance is present only to simplify usage.
</p>
<p>
<code class="computeroutput"><span class="identifier">xml_node</span></code> is the handle to
document node; it can point to any node in the document, including document
itself. There is a common interface for nodes of all types. Note that <code class="computeroutput"><span class="identifier">xml_node</span></code> is only a handle to the actual
node, not the node itself - you can have several <code class="computeroutput"><span class="identifier">xml_node</span></code>
handles pointing to the same underlying object. Destroying <code class="computeroutput"><span class="identifier">xml_node</span></code> handle does not destroy the node
and does not remove it from the tree.
</p>
<p>
There is a special value of <code class="computeroutput"><span class="identifier">xml_node</span></code>
type, known as null node or empty node. It does not correspond to any node
in any document, and thus resembles null pointer. However, all operations
are defined on empty nodes; generally the operations don't do anything and
return empty nodes/attributes or empty strings as their result. This is useful
for chaining calls; i.e. you can get the grandparent of a node like so:
<code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">parent</span><span class="special">().</span><span class="identifier">parent</span><span class="special">()</span></code>;
if a node is a null node or it does not have a parent, the first <code class="computeroutput"><span class="identifier">parent</span><span class="special">()</span></code>
call returns null node; the second <code class="computeroutput"><span class="identifier">parent</span><span class="special">()</span></code> call then also returns null node, so you
don't have to check for errors twice. You can test if a handle is null via
implicit boolean cast: <code class="computeroutput"><span class="keyword">if</span> <span class="special">(</span><span class="identifier">node</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>
or <code class="computeroutput"><span class="keyword">if</span> <span class="special">(!</span><span class="identifier">node</span><span class="special">)</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">xml_attribute</span></code> is the handle
to an XML attribute; it has the same semantics as <code class="computeroutput"><span class="identifier">xml_node</span></code>,
i.e. there can be several <code class="computeroutput"><span class="identifier">xml_attribute</span></code>
handles pointing to the same underlying object and there is a special null
attribute value, which propagates to function results.
</p>
<p>
There are two choices of interface and internal representation when configuring
pugixml: you can either choose the UTF-8 (also called char) interface or
UTF-16/32 (also called wchar_t) one. The choice is controlled via <code class="computeroutput"><span class="identifier">PUGIXML_WCHAR_MODE</span></code> define; you can set
it via <code class="filename">pugiconfig.hpp</code> or via preprocessor options. All tree functions that
work with strings work with either C-style null terminated strings or STL
strings of the selected character type. <a href="manual/dom.html#manual.dom.unicode" target="_top">Read
the manual</a> for additional information on Unicode interface.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.loading"></a><a class="link" href="quickstart.html#quickstart.main.loading" title="Loading document"> Loading document</a>
</h3></div></div></div>
<p>
pugixml provides several functions for loading XML data from various places
- files, C++ iostreams, memory buffers. All functions use an extremely fast
non-validating parser. This parser is not fully W3C conformant - it can load
any valid XML document, but does not perform some well-formedness checks.
While considerable effort is made to reject invalid XML documents, some validation
is not performed because of performance reasons. XML data is always converted
to internal character format before parsing. pugixml supports all popular
Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and
little endian); UCS-2 is naturally supported since it's a strict subset of
UTF-16) and handles all encoding conversions automatically.
</p>
<p>
The most common source of XML data is files; pugixml provides a separate
function for loading XML document from file. This function accepts file path
as its first argument, and also two optional arguments, which specify parsing
options and input data encoding, which are described in the manual.
</p>
<p>
This is an example of loading XML document from file (<a href="samples/load_file.cpp" target="_top">samples/load_file.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_file</span><span class="special">(</span><span class="string">"tree.xml"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Load result: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">description</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">", mesh name: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"mesh"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
<code class="computeroutput"><span class="identifier">load_file</span></code>, as well as other
loading functions, destroys the existing document tree and then tries to
load the new tree from the specified file. The result of the operation is
returned in an <code class="computeroutput"><span class="identifier">xml_parse_result</span></code>
object; this object contains the operation status, and the related information
(i.e. last successfully parsed position in the input file, if parsing fails).
</p>
<p>
Parsing result object can be implicitly converted to <code class="computeroutput"><span class="keyword">bool</span></code>;
if you do not want to handle parsing errors thoroughly, you can just check
the return value of load functions as if it was a <code class="computeroutput"><span class="keyword">bool</span></code>:
<code class="computeroutput"><span class="keyword">if</span> <span class="special">(</span><span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_file</span><span class="special">(</span><span class="string">"file.xml"</span><span class="special">))</span> <span class="special">{</span> <span class="special">...</span>
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span> <span class="special">...</span> <span class="special">}</span></code>.
Otherwise you can use the <code class="computeroutput"><span class="identifier">status</span></code>
member to get parsing status, or the <code class="computeroutput"><span class="identifier">description</span><span class="special">()</span></code> member function to get the status in a
string form.
</p>
<p>
This is an example of handling loading errors (<a href="samples/load_error_handling.cpp" target="_top">samples/load_error_handling.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_document</span> <span class="identifier">doc</span><span class="special">;</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">source</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">result</span><span class="special">)</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"XML ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span> <span class="special">&lt;&lt;</span> <span class="string">"] parsed without errors, attr value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"attr"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n\n"</span><span class="special">;</span>
<span class="keyword">else</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"XML ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span> <span class="special">&lt;&lt;</span> <span class="string">"] parsed with errors, attr value: ["</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"attr"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Error description: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">description</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Error offset: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">offset</span> <span class="special">&lt;&lt;</span> <span class="string">" (error at [..."</span> <span class="special">&lt;&lt;</span> <span class="special">(</span><span class="identifier">source</span> <span class="special">+</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">offset</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"]\n\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Sometimes XML data should be loaded from some other source than file, i.e.
HTTP URL; also you may want to load XML data from file using non-standard
functions, i.e. to use your virtual file system facilities or to load XML
from gzip-compressed files. These scenarios either require loading document
from memory, in which case you should prepare a contiguous memory block with
all XML data and to pass it to one of buffer loading functions, or loading
document from C++ IOstream, in which case you should provide an object which
implements <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code> or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">wistream</span></code>
interface.
</p>
<p>
There are different functions for loading document from memory; they treat
the passed buffer as either an immutable one (<code class="computeroutput"><span class="identifier">load_buffer</span></code>),
a mutable buffer which is owned by the caller (<code class="computeroutput"><span class="identifier">load_buffer_inplace</span></code>),
or a mutable buffer which ownership belongs to pugixml (<code class="computeroutput"><span class="identifier">load_buffer_inplace_own</span></code>).
There is also a simple helper function, <code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">load</span></code>,
for cases when you want to load the XML document from null-terminated character
string.
</p>
<p>
This is an example of loading XML document from memory using one of these
functions (<a href="samples/load_memory.cpp" target="_top">samples/load_memory.cpp</a>);
read the sample code for more examples:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">const</span> <span class="keyword">char</span> <span class="identifier">source</span><span class="special">[]</span> <span class="special">=</span> <span class="string">"&lt;mesh name='sphere'&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;"</span><span class="special">;</span>
<span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">source</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
</span><span class="keyword">char</span><span class="special">*</span> <span class="identifier">buffer</span> <span class="special">=</span> <span class="keyword">new</span> <span class="keyword">char</span><span class="special">[</span><span class="identifier">size</span><span class="special">];</span>
<span class="identifier">memcpy</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">source</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
<span class="comment">// The block can be allocated by any method; the block is modified during parsing
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load_buffer_inplace</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span>
<span class="comment">// You have to destroy the block yourself after the document is no longer used
</span><span class="keyword">delete</span><span class="special">[]</span> <span class="identifier">buffer</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
This is a simple example of loading XML document from file using streams
(<a href="samples/load_stream.cpp" target="_top">samples/load_stream.cpp</a>); read
the sample code for more complex examples involving wide streams and locales:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ifstream</span> <span class="identifier">stream</span><span class="special">(</span><span class="string">"weekly-utf-8.xml"</span><span class="special">);</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_parse_result</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">stream</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.access"></a><a class="link" href="quickstart.html#quickstart.main.access" title="Accessing document data"> Accessing document data</a>
</h3></div></div></div>
<p>
pugixml features an extensive interface for getting various types of data
from the document and for traversing the document. You can use various accessors
to get node/attribute data, you can traverse the child node/attribute lists
via accessors or iterators, you can do depth-first traversals with <code class="computeroutput"><span class="identifier">xml_tree_walker</span></code> objects, and you can use
XPath for complex data-driven queries.
</p>
<p>
You can get node or attribute name via <code class="computeroutput"><span class="identifier">name</span><span class="special">()</span></code> accessor, and value via <code class="computeroutput"><span class="identifier">value</span><span class="special">()</span></code> accessor. Note that both functions never
return null pointers - they either return a string with the relevant content,
or an empty string if name/value is absent or if the handle is null. Also
there are two notable things for reading values:
</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
It is common to store data as text contents of some node - i.e. <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;&lt;</span><span class="identifier">description</span><span class="special">&gt;</span><span class="identifier">This</span>
<span class="identifier">is</span> <span class="identifier">a</span>
<span class="identifier">node</span><span class="special">&lt;/</span><span class="identifier">description</span><span class="special">&gt;&lt;/</span><span class="identifier">node</span><span class="special">&gt;</span></code>.
In this case, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">description</span><span class="special">&gt;</span></code> node does not have a value, but instead
has a child of type <code class="computeroutput"><span class="identifier">node_pcdata</span></code>
with value <code class="computeroutput"><span class="string">"This is a node"</span></code>.
pugixml provides <code class="computeroutput"><span class="identifier">child_value</span><span class="special">()</span></code> helper functions to parse such data.
</li>
<li class="listitem">
In many cases attribute values have types that are not strings - i.e.
an attribute may always contain values that should be treated as integers,
despite the fact that they are represented as strings in XML. pugixml
provides several accessors that convert attribute value to some other
type.
</li>
</ul></div>
<p>
This is an example of using these functions (<a href="samples/traverse_base.cpp" target="_top">samples/traverse_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">))</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">": AllowRemote "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"AllowRemote"</span><span class="special">).</span><span class="identifier">as_bool</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", Timeout "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Timeout"</span><span class="special">).</span><span class="identifier">as_int</span><span class="special">();</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", Description '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">child_value</span><span class="special">(</span><span class="string">"Description"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Since a lot of document traversal consists of finding the node/attribute
with the correct name, there are special functions for that purpose. For
example, <code class="computeroutput"><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">)</span></code>
returns the first node which has the name <code class="computeroutput"><span class="string">"Tool"</span></code>,
or null handle if there is no such node. This is an example of using such
functions (<a href="samples/traverse_base.cpp" target="_top">samples/traverse_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool for *.dae generation: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">find_child_by_attribute</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">,</span> <span class="string">"OutputFileMasks"</span><span class="special">,</span> <span class="string">"*.dae"</span><span class="special">).</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">);</span> <span class="identifier">tool</span><span class="special">;</span> <span class="identifier">tool</span> <span class="special">=</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">next_sibling</span><span class="special">(</span><span class="string">"Tool"</span><span class="special">))</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool "</span> <span class="special">&lt;&lt;</span> <span class="identifier">tool</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
Child node lists and attribute lists are simply double-linked lists; while
you can use <code class="computeroutput"><span class="identifier">previous_sibling</span></code>/<code class="computeroutput"><span class="identifier">next_sibling</span></code> and other such functions for
iteration, pugixml additionally provides node and attribute iterators, so
that you can treat nodes as containers of other nodes or attributes. All
iterators are bidirectional and support all usual iterator operations. The
iterators are invalidated if the node/attribute objects they're pointing
to are removed from the tree; adding nodes/attributes does not invalidate
any iterators.
</p>
<p>
Here is an example of using iterators for document traversal (<a href="samples/traverse_iter.cpp" target="_top">samples/traverse_iter.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node_iterator</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> <span class="identifier">it</span> <span class="special">!=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">it</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tool:"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute_iterator</span> <span class="identifier">ait</span> <span class="special">=</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">attributes_begin</span><span class="special">();</span> <span class="identifier">ait</span> <span class="special">!=</span> <span class="identifier">it</span><span class="special">-&gt;</span><span class="identifier">attributes_end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">ait</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">ait</span><span class="special">-&gt;</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"="</span> <span class="special">&lt;&lt;</span> <span class="identifier">ait</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
The methods described above allow traversal of immediate children of some
node; if you want to do a deep tree traversal, you'll have to do it via a
recursive function or some equivalent method. However, pugixml provides a
helper for depth-first traversal of a subtree. In order to use it, you have
to implement <code class="computeroutput"><span class="identifier">xml_tree_walker</span></code>
interface and to call <code class="computeroutput"><span class="identifier">traverse</span></code>
function.
</p>
<p>
This is an example of traversing tree hierarchy with xml_tree_walker (<a href="samples/traverse_walker.cpp" target="_top">samples/traverse_walker.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">simple_walker</span><span class="special">:</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_tree_walker</span>
<span class="special">{</span>
<span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="identifier">for_each</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">node</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special">&lt;</span> <span class="identifier">depth</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span><span class="special">;</span> <span class="comment">// indentation
</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node_types</span><span class="special">[</span><span class="identifier">node</span><span class="special">.</span><span class="identifier">type</span><span class="special">()]</span> <span class="special">&lt;&lt;</span> <span class="string">": name='"</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"', value='"</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span> <span class="comment">// continue traversal
</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">simple_walker</span> <span class="identifier">walker</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">traverse</span><span class="special">(</span><span class="identifier">walker</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
Finally, for complex queries often a higher-level DSL is needed. pugixml
provides an implementation of XPath 1.0 language for such queries. The complete
description of XPath usage can be found in the manual, but here are some
examples:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span> <span class="identifier">tools</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_nodes</span><span class="special">(</span><span class="string">"/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Tools:"</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node_set</span><span class="special">::</span><span class="identifier">const_iterator</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> <span class="identifier">it</span> <span class="special">!=</span> <span class="identifier">tools</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span> <span class="special">++</span><span class="identifier">it</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="special">*</span><span class="identifier">it</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span>
<span class="special">}</span>
<span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xpath_node</span> <span class="identifier">build_tool</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">select_single_node</span><span class="special">(</span><span class="string">"//Tool[contains(Description, 'build system')]"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nBuild tool: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">build_tool</span><span class="special">.</span><span class="identifier">node</span><span class="special">().</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"Filename"</span><span class="special">).</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
</pre>
<p>
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
XPath functions throw <code class="computeroutput"><span class="identifier">xpath_exception</span></code>
objects on error; the sample above does not catch these exceptions.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.modify"></a><a class="link" href="quickstart.html#quickstart.main.modify" title="Modifying document data"> Modifying document data</a>
</h3></div></div></div>
<p>
The document in pugixml is fully mutable: you can completely change the document
structure and modify the data of nodes/attributes. All functions take care
of memory management and structural integrity themselves, so they always
result in structurally valid tree - however, it is possible to create an
invalid XML tree (for example, by adding two attributes with the same name
or by setting attribute/node name to empty/invalid string). Tree modification
is optimized for performance and for memory consumption, so if you have enough
memory you can create documents from scratch with pugixml and later save
them to file/stream instead of relying on error-prone manual text writing
and without too much overhead.
</p>
<p>
All member functions that change node/attribute data or structure are non-constant
and thus can not be called on constant handles. However, you can easily convert
constant handle to non-constant one by simple assignment: <code class="computeroutput"><span class="keyword">void</span>
<span class="identifier">foo</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span><span class="special">&amp;</span> <span class="identifier">n</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">nc</span> <span class="special">=</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">}</span></code>, so const-correctness
here mainly provides additional documentation.
</p>
<p>
As discussed before, nodes can have name and value, both of which are strings.
Depending on node type, name or value may be absent. You can use <code class="computeroutput"><span class="identifier">set_name</span></code> and <code class="computeroutput"><span class="identifier">set_value</span></code>
member functions to set them. Similar functions are available for attributes;
however, the <code class="computeroutput"><span class="identifier">set_value</span></code> function
is overloaded for some other types except strings, like floating-point numbers.
Also, attribute value can be set using an assignment operator. This is an
example of setting node/attribute name and value (<a href="samples/modify_base.cpp" target="_top">samples/modify_base.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="comment">// change node name
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"notnode"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new node name: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// change comment text
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"useless comment"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new comment text: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can't change value of the element or name of the comment
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"1"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">", "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">last_child</span><span class="special">().</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"2"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"id"</span><span class="special">);</span>
<span class="comment">// change attribute name/value
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_name</span><span class="special">(</span><span class="string">"key"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">", "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"345"</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">", new attribute: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"="</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can use numbers or booleans
</span><span class="identifier">attr</span><span class="special">.</span><span class="identifier">set_value</span><span class="special">(</span><span class="number">1.234</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"new attribute value: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">// we can also use assignment operators for more concise code
</span><span class="identifier">attr</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"final attribute value: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">attr</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
Nodes and attributes do not exist without a document tree, so you can't create
them without adding them to some document. A node or attribute can be created
at the end of node/attribute list or before/after some other node. All insertion
functions return the handle to newly created object on success, and null
handle on failure. Even if the operation fails (for example, if you're trying
to add a child node to PCDATA node), the document remains in consistent state,
but the requested node/attribute is not added.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top"><p>
attribute() and child() functions do not add attributes or nodes to the
tree, so code like <code class="computeroutput"><span class="identifier">node</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"id"</span><span class="special">)</span> <span class="special">=</span> <span class="number">123</span><span class="special">;</span></code> will not do anything if <code class="computeroutput"><span class="identifier">node</span></code> does not have an attribute with
name <code class="computeroutput"><span class="string">"id"</span></code>. Make sure
you're operating with existing attributes/nodes by adding them if necessary.
</p></td></tr>
</table></div>
<p>
This is an example of adding new attributes/nodes to the document (<a href="samples/modify_add.cpp" target="_top">samples/modify_add.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// add node with some name
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="comment">// add description node with text child
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">descr</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="string">"description"</span><span class="special">);</span>
<span class="identifier">descr</span><span class="special">.</span><span class="identifier">append_child</span><span class="special">(</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">node_pcdata</span><span class="special">).</span><span class="identifier">set_value</span><span class="special">(</span><span class="string">"Simple node"</span><span class="special">);</span>
<span class="comment">// add param node before the description
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">insert_child_before</span><span class="special">(</span><span class="string">"param"</span><span class="special">,</span> <span class="identifier">descr</span><span class="special">);</span>
<span class="comment">// add attributes to param node
</span><span class="identifier">param</span><span class="special">.</span><span class="identifier">append_attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">)</span> <span class="special">=</span> <span class="string">"version"</span><span class="special">;</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">append_attribute</span><span class="special">(</span><span class="string">"value"</span><span class="special">)</span> <span class="special">=</span> <span class="number">1.1</span><span class="special">;</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">insert_attribute_after</span><span class="special">(</span><span class="string">"type"</span><span class="special">,</span> <span class="identifier">param</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">))</span> <span class="special">=</span> <span class="string">"float"</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
If you do not want your document to contain some node or attribute, you can
remove it with <code class="computeroutput"><span class="identifier">remove_attribute</span></code>
and <code class="computeroutput"><span class="identifier">remove_child</span></code> functions.
Removing the attribute or node invalidates all handles to the same underlying
object, and also invalidates all iterators pointing to the same object. Removing
node also invalidates all past-the-end iterators to its attribute or child
node list. Be careful to ensure that all such handles and iterators either
do not exist or are not used after the attribute/node is removed.
</p>
<p>
This is an example of removing attributes/nodes from the document (<a href="samples/modify_remove.cpp" target="_top">samples/modify_remove.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// remove description node with the whole subtree
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">node</span> <span class="special">=</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"node"</span><span class="special">);</span>
<span class="identifier">node</span><span class="special">.</span><span class="identifier">remove_child</span><span class="special">(</span><span class="string">"description"</span><span class="special">);</span>
<span class="comment">// remove id attribute
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_node</span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">node</span><span class="special">.</span><span class="identifier">child</span><span class="special">(</span><span class="string">"param"</span><span class="special">);</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="string">"value"</span><span class="special">);</span>
<span class="comment">// we can also remove nodes/attributes by handles
</span><span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_attribute</span> <span class="identifier">id</span> <span class="special">=</span> <span class="identifier">param</span><span class="special">.</span><span class="identifier">attribute</span><span class="special">(</span><span class="string">"name"</span><span class="special">);</span>
<span class="identifier">param</span><span class="special">.</span><span class="identifier">remove_attribute</span><span class="special">(</span><span class="identifier">id</span><span class="special">);</span>
</pre>
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.saving"></a><a class="link" href="quickstart.html#quickstart.main.saving" title="Saving document"> Saving document</a>
</h3></div></div></div>
<p>
Often after creating a new document or loading the existing one and processing
it, it is necessary to save the result back to file. Also it is occasionally
useful to output the whole document or a subtree to some stream; use cases
include debug printing, serialization via network or other text-oriented
medium, etc. pugixml provides several functions to output any subtree of
the document to a file, stream or another generic transport interface; these
functions allow to customize the output format, and also perform necessary
encoding conversions.
</p>
<p>
Before writing to the destination the node/attribute data is properly formatted
according to the node type; all special XML symbols, such as &lt; and &amp;,
are properly escaped. In order to guard against forgotten node/attribute
names, empty node/attribute names are printed as <code class="computeroutput"><span class="string">":anonymous"</span></code>.
For well-formed output, make sure all node and attribute names are set to
meaningful values.
</p>
<p>
If you want to save the whole document to a file, you can use the <code class="computeroutput"><span class="identifier">save_file</span></code> function, which returns <code class="computeroutput"><span class="keyword">true</span></code> on success. This is a simple example
of saving XML document to file (<a href="samples/save_file.cpp" target="_top">samples/save_file.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// save document to file
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Saving result: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">doc</span><span class="special">.</span><span class="identifier">save_file</span><span class="special">(</span><span class="string">"save_file_output.xml"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
</pre>
<p>
</p>
<p>
To enhance interoperability pugixml provides functions for saving document
to any object which implements C++ <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>
interface. This allows you to save documents to any standard C++ stream (i.e.
file stream) or any third-party compliant implementation (i.e. Boost Iostreams).
Most notably, this allows for easy debug output, since you can use <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>
stream as saving target. There are two functions, one works with narrow character
streams, another handles wide character ones.
</p>
<p>
This is a simple example of saving XML document to standard output (<a href="samples/save_stream.cpp" target="_top">samples/save_stream.cpp</a>):
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// save document to standard output
</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Document:\n"</span><span class="special">;</span>
<span class="identifier">doc</span><span class="special">.</span><span class="identifier">save</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
All of the above saving functions are implemented in terms of writer interface.
This is a simple interface with a single function, which is called several
times during output process with chunks of document data as input. In order
to output the document via some custom transport, for example sockets, you
should create an object which implements <code class="computeroutput"><span class="identifier">xml_writer_file</span></code>
interface and pass it to <code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span></code>
function.
</p>
<p>
This is a simple example of custom writer for saving document data to STL
string (<a href="samples/save_custom_writer.cpp" target="_top">samples/save_custom_writer.cpp</a>);
read the sample code for more complex examples:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">xml_string_writer</span><span class="special">:</span> <span class="identifier">pugi</span><span class="special">::</span><span class="identifier">xml_writer</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span><span class="special">;</span>
<span class="keyword">virtual</span> <span class="keyword">void</span> <span class="identifier">write</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">void</span><span class="special">*</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">result</span> <span class="special">+=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*&gt;(</span><span class="identifier">data</span><span class="special">),</span> <span class="identifier">size</span><span class="special">);</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
While the previously described functions save the whole document to the destination,
it is easy to save a single subtree. Instead of calling <code class="computeroutput"><span class="identifier">xml_document</span><span class="special">::</span><span class="identifier">save</span></code>,
just call <code class="computeroutput"><span class="identifier">xml_node</span><span class="special">::</span><span class="identifier">print</span></code> function on the target node. You
can save node contents to C++ IOstream object or custom writer in this way.
Saving a subtree slightly differs from saving the whole document; <a href="manual/saving.html#manual.saving.subtree" target="_top">read the manual</a> for
more information.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.feedback"></a><a class="link" href="quickstart.html#quickstart.main.feedback" title="Feedback"> Feedback</a>
</h3></div></div></div>
<p>
If you believe you've found a bug in pugixml, please file an issue via <a href="http://code.google.com/p/pugixml/issues/entry" target="_top">issue submission form</a>.
Be sure to include the relevant information so that the bug can be reproduced:
the version of pugixml, compiler version and target architecture, the code
that uses pugixml and exhibits the bug, etc. Feature requests and contributions
can be filed as issues, too.
</p>
<a name="email"></a><p>
If filing an issue is not possible due to privacy or other concerns, you
can contact pugixml author by e-mail directly: <a href="mailto:arseny.kapoulkine@gmail.com" target="_top">arseny.kapoulkine@gmail.com</a>.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="quickstart.main.license"></a><a class="link" href="quickstart.html#quickstart.main.license" title="License"> License</a>
</h3></div></div></div>
<p>
The pugixml library is distributed under the MIT license:
</p>
<div class="blockquote"><blockquote class="blockquote">
<p>
Copyright (c) 2006-2010 Arseny Kapoulkine
</p>
<p>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
</p>
<p>
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
</p>
</blockquote></div>
<p>
This means that you can freely use pugixml in your applications, both open-source
and proprietary. If you use pugixml in a product, it is sufficient to add
an acknowledgment like this to the product distribution:
</p>
<div class="blockquote"><blockquote class="blockquote"><p>
This software is based on pugixml library (http://pugixml.org).<br>
pugixml
is Copyright (C) 2006-2010 Arseny Kapoulkine.
</p></blockquote></div>
</div>
</div>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.trademarks" href="#trademarks" class="para">1</a>] </sup>All trademarks used are properties of their respective owners.</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: October 31, 2010 at 07:44:52 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
</body>
</html>
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<network>
<animation clip="idle" flags="loop" />
<animation clip="run" flags="loop" />
<animation clip="attack" />
<?include transitions.xml?>
</network>
@@ -0,0 +1,27 @@
#include "pugixml.hpp"
#include <new>
//[code_custom_memory_management_decl
void* custom_allocate(size_t size)
{
return new (std::nothrow) char[size];
}
void custom_deallocate(void* ptr)
{
delete[] static_cast<char*>(ptr);
}
//]
int main()
{
//[code_custom_memory_management_call
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
//]
pugi::xml_document doc;
doc.load("<node/>");
}
// vim:et

Some files were not shown because too many files have changed in this diff Show More