📄 xpathexpression.cpp
字号:
//**************************************************************************************************************************
//* 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 + -