📄 xml_parser.cpp
字号:
/////////////////////////////////////////////////////////////////////////
// 类名:XML_PARSER
// 功能:XML文件读写、解析包装类
// 附注:简化编程工作量
// 修订:徐景周(jingzhou_xu@163.com)
// 组织:Future Studio
// 日期:2005.5.9
// What's news ?
//
// 1. The parsing document start from document and not from root element
// - Let us to parse the header document informations
// 2. New XML header management
// - encoding format, stylesheet reference, etc...
// - Set_Header("xml","version","1.0")
// - Set_Header("xml","encoding","UTF-8"), etc...
// 3. New CData section management
// - We can now read and add CData section with method like "Add_LastChildCData(LPCTSTR data)"
// 4. Some new methods for more fun
// - like "Get_XML_Document()"
// 5. Minor design change for improve the class
// - Some methods have been renamed like "Get_Text()" to "Get_TextValue()"
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdafx.h>
#include <atlbase.h>
#include "XML_PARSER.h"
//using namespace MSXML2; // 为避免于老版本名字空间冲突,改为导入老版本,jingzhou xu,2005.5.17
XML_PARSER::XML_PARSER()
{ // Constructor
// Init our members
//
this->AttribNames.RemoveAll();
this->AttribValues.RemoveAll();
this->Tag.Empty();
this->Name.Empty();
this->ChainTag.Empty();
this->TextField.Empty();
// Init MSXML members
//
CurrentNode = NULL;
m_plDomDocument = NULL;
m_pDocRoot = NULL;
attrib_index = -1;
// -- Errors Init --
//
ok.Empty();
ok = "Success";
lasterror = ok;
}
XML_PARSER::~XML_PARSER()
{ // Free ressource
//
this->Reset_XML_Document();
}
CString & XML_PARSER::Get_LastError()
{ return lasterror; }
bool XML_PARSER::Init_MSXML()
{
lasterror = ok;
// -- Init OLE Object Comunication for MSXML (only once time)--
//
static bool ole_initialized = false;
if( !ole_initialized )
{
::AfxOleInit(); // 初始化
ole_initialized = true;
}
// -- Instantiate an XML document --
//
HRESULT hr = m_plDomDocument.CreateInstance(MSXML::CLSID_DOMDocument);
if( FAILED(hr) )
{
_com_error er(hr);
lasterror = er.ErrorMessage();
return false;
}
return true;
}
bool XML_PARSER::Load_XML_Document(LPCTSTR strFileName)
{
lasterror = ok;
// Reset Document
//
this->Reset_XML_Document();
// Convert xml file name string to something COM can handle (BSTR)
//
CString sFileName = strFileName;
_bstr_t bstrFileName;
bstrFileName = sFileName.AllocSysString();
// Call the IXMLDOMDocumentPtr's load function to load the XML document
//
variant_t vResult;
vResult = m_plDomDocument->load(bstrFileName);
if( ((bool)vResult) == TRUE ) // success!
{
// Now that the document is loaded, we need to initialize the root pointer
//
m_pDocRoot = m_plDomDocument->documentElement;
// Now we can Parse this document !!
//
Parse_Objects(m_plDomDocument);
this->Go_to_Root();
return true;
}
else
{ // XML document is not loaded, return error
//
lasterror = "XML Document FAILED to load";
return false;
}
}
void XML_PARSER::Load_XML_From_Buffer(LPCTSTR source)
{
// Reset the document
//
this->Reset_XML_Document();
// Load from Buffer
//
m_plDomDocument->loadXML(source);
m_pDocRoot = m_plDomDocument->documentElement;
// Start the Parsing
//
Parse_Objects(m_plDomDocument);
// Move to the root node
//
this->Go_to_Root();
}
void XML_PARSER::Get_XML(CString & buffer)
{
if(this->CurrentNode == this->m_pDocRoot)
this->Get_XML_Document(buffer);
else
{ BSTR b_xml;
this->CurrentNode->get_xml(&b_xml);
buffer = b_xml;
}
}
void XML_PARSER::Get_XML_Document(CString & buffer)
{
BSTR b_xml;
this->m_plDomDocument->get_xml(&b_xml);
buffer = b_xml;
}
bool XML_PARSER::Parse_XML_Document()
{
/* Nothing to do , this method will be redefined in derived class */
return false;
}
void XML_PARSER::Parse_Objects(MSXML::IXMLDOMNodePtr pObject)
{
// Child node
//
MSXML::IXMLDOMNodePtr pChild;
// Grab Informations from the pObject node
//
this->Grab_Node_Informations(pObject);
// Update "CurrentNode"
//
this->CurrentNode = pObject;
// Call User Parse Handling for let him what he want.
//
this->Parse_XML_Document();
if(Is_MSXML_Node(pObject) != MSXML::NODE_ELEMENT)
return;
// add the ChainTag
//
this->ChainTag_Add(this->Tag);
for (pChild = pObject->firstChild; NULL != pChild; pChild = pChild->nextSibling)
{
// Parse Child nodes
//
this->Parse_Objects(pChild);
}
// Remove Current Tag from ChainTag
//
ChainTag_Remove(1);
}
bool XML_PARSER::Is_Tag(LPCTSTR aTag)
{
return this->Get_CurrentTag() == aTag;
}
bool XML_PARSER::Is_TextNode()
{
return (this->Is_Tag("<#TEXT#>"));
}
bool XML_PARSER::Is_CDataSection()
{
return (this->Is_Tag("<#CDATA#>"));
}
CString & XML_PARSER::Get_CurrentTag()
{ return this->Tag; }
CString & XML_PARSER::Get_CurrentName()
{
return this->Name;
}
bool XML_PARSER::Is_Root()
{
return (this->ChainTag.IsEmpty() != 0);
}
bool XML_PARSER::Is_Child_of(LPCTSTR parent_chain)
{
int pos = this->ChainTag.Find(parent_chain);
int len = strlen(parent_chain);
if(pos != -1)
{ // look if it's the end of this chainTag
//
return ( this->ChainTag.GetLength() == pos + len );
}
return false;
}
CString & XML_PARSER::Get_TextValue()
{ // Now you can handle the text value on the real node directly if you want
if(Is_MSXML_Node(this->CurrentNode) == MSXML::NODE_TEXT || Is_MSXML_Node(this->CurrentNode) == MSXML::NODE_CDATA_SECTION)
return this->TextField;
// We must find his text value
//
CString TextValue;
// Find if a CHILD TEXT NODE exist or not
//
if(CurrentNode == NULL)
{ if(this->m_pDocRoot != NULL)
this->CurrentNode = this->m_pDocRoot;
else
{ // We can't set the text
//
lasterror = "XML_PARSER::Get_TextValue() Can't set text on NULL node";
this->TextField = "";
return this->TextField;
}
}
// Find it now
//
if(this->CurrentNode->hasChildNodes())
{
MSXML::IXMLDOMNodePtr pChild;
for(pChild = this->CurrentNode->firstChild; pChild != NULL; pChild = pChild->nextSibling)
{ // Find it's a NODE TEXT
//
if(this->Is_MSXML_Node(pChild) == MSXML::NODE_TEXT)
{ // Take informations from this Text Node
//
this->Grab_Node_Informations(pChild);
TextValue = this->TextField;
this->Grab_Node_Informations(this->CurrentNode); // it remove this->TextField
this->TextField = TextValue;
return (this->TextField);
}
}
}
this->TextField = "";
return (this->TextField);
}
HRESULT XML_PARSER::Is_MSXML_Node(MSXML::IXMLDOMNodePtr pChild)
{
if(pChild == NULL) return NULL;
// I handle only few node type other are ignored and are considered as NODE_ELEMENT
//
// Handled Node type by this wrapper:
// - NODE_ELEMENT
// - NODE_TEXT
// - NODE_CDATA_SECTION
// - NODE_PROCESSING_INSTRUCTION
if(pChild->nodeType == MSXML::NODE_TEXT) return MSXML::NODE_TEXT;
if(pChild->nodeType == MSXML::NODE_CDATA_SECTION) return MSXML::NODE_CDATA_SECTION;
if(pChild->nodeType == MSXML::NODE_PROCESSING_INSTRUCTION ) return MSXML::NODE_PROCESSING_INSTRUCTION;
return MSXML::NODE_ELEMENT;
}
void XML_PARSER::Grab_Node_Informations(MSXML::IXMLDOMNodePtr pChild)
{
if(this->Is_MSXML_Node(pChild) == MSXML::NODE_ELEMENT)
{ // It's a node
//
// Tag Update
//
Tag.Format("<%s>",(const char*)(pChild->nodeName));
Name = (const char*)(pChild->nodeName);
// TextField no significant value
TextField.Empty();
// Update Attribute List
//
this->AttribNames.RemoveAll();
this->AttribValues.RemoveAll();
MSXML::IXMLDOMNamedNodeMapPtr pAttribs = pChild->Getattributes();
if(pAttribs != NULL)
{ long nAttriCnt = pAttribs->Getlength();
// Iterate over the attributes
//
for(int i=0; i<nAttriCnt; ++i)
{ MSXML::IXMLDOMNodePtr pAttrib = pAttribs->Getitem(i);
if(pAttrib != NULL)
{
this->AttribNames.Add( (CString)(const char *) pAttrib->GetnodeName() );
_variant_t vVal = pAttrib->GetnodeValue ( );
this->AttribValues.Add( (CString)(const char *) _bstr_t(vVal) );
}
}
}
}
else if (this->Is_MSXML_Node(pChild) == MSXML::NODE_TEXT)
{ // Tag is #TEXT#
//
Tag.Empty();
Tag = "<#TEXT#>";
Name.Empty();
Name = "#TEXT#";
// TextField Update
//
TextField = (const char*)(pChild->text);
// Update Attribute List have no means
//
this->AttribNames.RemoveAll();
this->AttribValues.RemoveAll();
}
else if (this->Is_MSXML_Node(pChild) == MSXML::NODE_CDATA_SECTION)
{ // Tag is #CDATA#
//
Tag.Empty();
Tag = "<#CDATA#>";
Name.Empty();
Name = "#CDATA#";
// TextField Update
//
TextField = (const char*)(pChild->text);
// Update Attribute List have no means
//
this->AttribNames.RemoveAll();
this->AttribValues.RemoveAll();
}
else if (this->Is_MSXML_Node(pChild) == MSXML::NODE_PROCESSING_INSTRUCTION)
{ /* Do nothing here */ }
return;
}
void XML_PARSER::ChainTag_Add(CString & val)
{
// Add a tag to the ChainTag
//
if(!ChainTag.IsEmpty())
ChainTag += val;
else
ChainTag = val;
}
void XML_PARSER::ChainTag_Remove(int number)
{
// Remove the n tag to the ChainTag
//
for(int bcl = 0; bcl < number; bcl ++)
{
int pos = ChainTag.ReverseFind('<');
if(pos == -1)
ChainTag.Empty();
else
ChainTag = ChainTag.Left(pos);
}
}
int XML_PARSER::Get_Attribute_Count()
{
return this->AttribNames.GetSize();
}
CString & XML_PARSER::Get_Attribute_Name(int index)
{
lasterror = "XML_PARSER::Get_Attribute_Name(int) failed";
if(index < 0 || index > this->Get_Attribute_Count())
{ tmp.Empty();
return tmp;
}
lasterror = ok;
return this->AttribNames[index];
}
CString & XML_PARSER::Get_Attribute_Value(int index)
{
lasterror = "XML_PARSER::Get_Attribute_Value(int) failed";
if(index < 0 || index > this->Get_Attribute_Count())
{ tmp.Empty();
return tmp;
}
lasterror = ok;
return this->AttribValues[attrib_index];
}
bool XML_PARSER::Is_Having_Attribute(LPCTSTR Name)
{
// Create the CString Name Object
//
CString sName = Name;
// Clear attribute index
//
attrib_index = -1;
int bcl;
for(bcl = 0; bcl < this->Get_Attribute_Count() ; bcl++)
{ // Check if the name is equal
//
if(this->AttribNames[bcl] == sName)
{ // set index fot let user to retrieve value with "Get_Attribute_Value()" method
//
attrib_index = bcl;
return true;
}
}
return false;
}
CString & XML_PARSER::Get_Attribute_Value()
{ // Assume Success
//
lasterror = ok;
if(attrib_index != -1)
return this->AttribValues[attrib_index];
// We can't retrieve a Attribute values
//
lasterror = "XML_PARSER::Get_Attribute_Value() : Can't Retrieve an Attribute";
return lasterror;
}
bool XML_PARSER::_add_lastchild(MSXML::IXMLDOMNodePtr newNode)
{ // Attach the Node to the document
//
if(CurrentNode != NULL)
{ if(Is_MSXML_Node(this->CurrentNode) != MSXML::NODE_ELEMENT) return false;
this->ChainTag_Add( this->Get_CurrentTag() );
newNode = CurrentNode->appendChild(newNode);
}
else if(m_pDocRoot != NULL)
{ if(Is_MSXML_Node(this->m_pDocRoot) != MSXML::NODE_ELEMENT) return false;
this->ChainTag_Add( (CString)(const char*)m_pDocRoot->nodeName );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -