⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpathexpression.cpp

📁 简单的xml解析类
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//************************************************************************************************************************** 
//* Blue Xml Extension
//* Copyright (c) 2002-2004 Josh Harler
//* 
//* Blue - General Purpose C++ Library
//* Copyright (c) 2002-2004 Josh Harler
//* 
//* This software is provided 'as-is', without any express or implied warranty. In no event
//* will the authors be held liable for any damages arising from the use of this software.
//* 
//* Permission is granted to anyone to use this software for any purpose, including commercial
//* applications, and to alter it and redistribute it freely, subject to the following restrictions:
//* 
//* 	1. The origin of this software must not be misrepresented; you must not claim that you
//* 	wrote the original software. If you use this software in a product, an acknowledgment in the
//* 	product documentation would be appreciated but is not required.
//* 
//* 	2. Altered source versions must be plainly marked as such, and must not be misrepresented as
//* 	being the original software.
//* 
//* 	3. This notice may not be removed or altered from any source distribution.
//*
//*
//* file   Blue/Extension/Xml/XPathExpression.cpp
//**

// Private Headers =========================================================================================================

// matching header
#include "XPathExpression.h"

// Blue library headers
#include "Blue/Util/StringTokenizer.h"

// Extension headers
#include "Blue/Extension/Xml/internal/XPathPredicate.h"


// Private Defines/Enums/Typedefs/Etc ======================================================================================

using namespace blue;
using namespace blue::common;
using namespace blue::util;


// Private Classes/Structs =================================================================================================

// Private Global Variables ================================================================================================

namespace {

	const String AXIS_CHILD               = $("child");
	const String AXIS_DESCENDANT          = $("descendant");
	const String AXIS_PARENT              = $("parent");
	const String AXIS_ANCESTOR            = $("ancestor");
	const String AXIS_FOLLOWING_SIBLING   = $("following-sibling");
	const String AXIS_PRECEDING_SIBLING   = $("preceding-sibling");
	const String AXIS_FOLLOWING           = $("following");
	const String AXIS_PRECEDING           = $("preceding");
	const String AXIS_DESCENDANT_OR_SELF  = $("descendant-or-self");
	const String AXIS_ANCESTOR_OR_SELF    = $("ancestor-or-self");
	const String AXIS_SELF                = $("self");
	const String AXIS_ATTRIBUTE           = $("attribute");
}


// External Global Variables ===============================================================================================

// Private Functions =======================================================================================================

namespace {
	using namespace blue::ext;
	using namespace blue::ext::xml;


	Array<int> priv_sortGetIDs( DomNode* node )
	{
		Array<int> id;
		Array<DomNode*> siblings;

		DomNode* parent = node->getParent();
		if( parent != 0 ) {
			siblings = parent->getSubNodes();
			id = priv_sortGetIDs(parent);
		}
		else {
			siblings = Array<DomNode*>(1);
			siblings[0] = node;
		}

		for( int i = 0; i < siblings.getSize(); ++i ) {
			if( siblings[i] == node ) {
				id.append(i);
				break;
			}
		}

		return (id);
	}


	int priv_sortCompareIDs( Array<int> one, Array<int> two )
	{
		int oneSize = one.getSize();
		int twoSize = two.getSize();
		int maxSize = min(oneSize, twoSize);

		for( int i = 0; i < maxSize; ++i ) {
			if( one[i] < two[i] ) {
				return (-1);
			}
			if( one[i] > two[i] ) {
				return (1);
			}
		}

		if( oneSize < twoSize ) {
			return (-1);
		}
		if( oneSize > twoSize ) {
			return (1);
		}

		return (0);
	}


	Array<DomNode*> priv_sortDocumentOrder( Array<DomNode*> nodes )
	{
		Array<DomNode*> wrkNodes = nodes.copy();
		Array< Array<int> > wrkIDs(wrkNodes.getSize());
		int idx;

		for( idx = 0; idx < wrkNodes.getSize(); ++idx ) {
			wrkIDs[idx] = priv_sortGetIDs(wrkNodes[idx]);
		}

		Array<DomNode*> srtNodes(wrkNodes.getSize());
		int srtIdx = 0;

		while(srtIdx < srtNodes.getSize()) {
			int idxLow = -1;

			for( idx = 0; idx < wrkIDs.getSize(); ++idx ) {
				if( wrkIDs[idx].getSize() > 0 ) {
					if( idxLow == -1 ) {
						idxLow = idx;
					}
					else {
						int compare = priv_sortCompareIDs(wrkIDs[idx], wrkIDs[idxLow]);
						if( compare < 0 ) {
							idxLow = idx;
						}
						if( compare == 0 ) {
							// remove any duplicates
							wrkIDs[idx].clear();
						}
					}
				}
			}

			if( idxLow == -1 ) {
				break;
			}

			srtNodes[srtIdx++] = wrkNodes[idxLow];
			wrkIDs[idxLow].clear();
		}

		if( srtIdx != srtNodes.getSize() ) {
			srtNodes.resize(srtIdx);
		}
		
		return (srtNodes);
	}

}


// Functions ===============================================================================================================

namespace blue {
namespace ext {
namespace xml {

	// ---------------------------------------------------------------------------------------------------------------------

	XPathExpression::XPathExpression() :m_root(0), m_predicate(0)
	{
	}

	// ---------------------------------------------------------------------------------------------------------------------

	XPathExpression::XPathExpression( DomNode* root ) :m_root(root), m_predicate(0)
	{
	}

	// ---------------------------------------------------------------------------------------------------------------------

	XPathExpression::~XPathExpression()
	{
		if( m_predicate != 0 ) {
			delete m_predicate;
		}
	}

	// ---------------------------------------------------------------------------------------------------------------------

	DomNode* XPathExpression::getRootNode()
	{
		return (m_root);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	const DomNode* XPathExpression::getRootNode() const
	{
		return (m_root);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	XPathFunction* XPathExpression::getFunction( String function )
	{
		if( m_predicate != 0 ) {
			return m_predicate->getFunction(function);
		}

		return (0);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	const XPathFunction* XPathExpression::getFunction( String function ) const
	{
		return ((XPathExpression*)this)->getFunction(function);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	Array<DomNode*> XPathExpression::findNodes( String xpathExpr )
	{
		Array< Array<xp_path_item> > info;
		extractInfo(xpathExpr, info);

		Array<DomNode*> matches;
		for( int i = 0; i < info.getSize(); ++i ) {
			Array<xp_path_item>& items = info[i];

			Array<DomNode*> search(1);
			search[0] = m_root;

			for( int iPi = 0; iPi < items.getSize(); ++iPi ) {
				Array<DomNode*> results = processPass(search, items[iPi]);
				search = results;
			}

			matches += search;
		}

		matches = priv_sortDocumentOrder(matches);
		return (matches);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	const Array<DomNode*> XPathExpression::findNodes( String xpathExpr ) const
	{
		return ((XPathExpression*)this)->findNodes(xpathExpr);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	Array<String> XPathExpression::findValues( String xpathExpr ) const
	{
		const Array<DomNode*> nodes = findNodes(xpathExpr);
		Array<String> results(nodes.getSize());

		for( int i = 0; i < nodes.getSize(); ++i ) {
			results[i] = nodes[i]->getValue();
		}

		return (results);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	DomNode* XPathExpression::findNode( String xpathExpr )
	{
		Array<DomNode*> nodes = findNodes(xpathExpr);
		if( nodes.getSize() > 0 ) {
			return (nodes[0]);
		}

		return (0);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	const DomNode* XPathExpression::findNode( String xpathExpr ) const
	{
		return ((XPathExpression*)this)->findNode(xpathExpr);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	String XPathExpression::findValue( String xpathExpr ) const
	{
		Array<String> values = findValues(xpathExpr);
		if( values.getSize() > 0 ) {
			return (values[0]);
		}

		return (String::null);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	void XPathExpression::setRootNode( DomNode* root )
	{
		m_root = root;
	}

	// ---------------------------------------------------------------------------------------------------------------------

	void XPathExpression::addFunction( XPathFunction* function )
	{
		if( m_predicate == 0 ) {
			m_predicate = new XPathPredicate();
		}
		m_predicate->addFunction(function);
	}

	// ---------------------------------------------------------------------------------------------------------------------
		
	void XPathExpression::removeFunction( String function )
	{
		if( m_predicate != 0 ) {
			m_predicate->removeFunction(function);
		}
	}

	// ---------------------------------------------------------------------------------------------------------------------

	void XPathExpression::extractInfo( String xpathExpr, Array< Array<xp_path_item> >& info )
	{
		StringTokenizer toker;
		toker.addContainer($("\""), $("\""), StringTokenizer::EXCLUSIVE);
		toker.addContainer($("\'"), $("\'"), StringTokenizer::EXCLUSIVE);
		toker.addContainer($("[" ), $("]" ), StringTokenizer::NORMAL   );
		flags32_t tokerFlags = StringTokenizer::KEEP_DELIMITERS|StringTokenizer::TRIM_RESULTS|StringTokenizer::NO_WHITESPACE;

		Array<String> tokens = toker.tokenize(xpathExpr, $("/|"), tokerFlags);

		Array<xp_path_item> curInfo;

		int idx = 0;
		while( idx < tokens.getSize() ) {

			if( tokens[idx] == "|" ) {
				if( ++idx == tokens.getSize() ) {
					break;
				}

				info.append(curInfo);
				curInfo.clear();
			}

			if( tokens[idx] != "/" || ++idx == tokens.getSize() ) {
				throw XPathException("Invalid XPath expression: '" + xpathExpr + "'");
			}

			// check for "//" shortcut

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -