@@ -7438,27 +7438,50 @@ static bool isBoxingNode(ldomNode * pNode)
74387438 return false;
74397439}
74407440
7441- static ldomNode * getNodebyIndex(ldomNode *parent, int index, int& count)
7441+ static bool isTextNode(ldomNode * node)
7442+ {
7443+ return (node && node->isText());
7444+ }
7445+
7446+ struct ldomNodeIdPredicate
7447+ {
7448+ lUInt16 m_id;
7449+ ldomNodeIdPredicate(lUInt16 id) : m_id(id) {}
7450+ bool operator() (ldomNode * node) {
7451+ return (node && node->getNodeId() == m_id);
7452+ }
7453+ };
7454+
7455+ static bool notNull(ldomNode * node)
7456+ {
7457+ return (NULL != node);
7458+ }
7459+
7460+ template<typename T>
7461+ static ldomNode * getNodebyIndex(ldomNode *parent, int index, T predicat, int& count)
74427462{
74437463 ldomNode *foundNode = NULL;
74447464
74457465 for( int i=0; i < (int)parent->getChildCount(); i++) {
74467466 ldomNode * p = parent->getChildNode(i);
7447- if( isBoxingNode(p) )
7448- foundNode = getNodebyIndex(p, index, count);
7449- else
7467+ if( isBoxingNode(p) ) {
7468+ foundNode = getNodebyIndex(p, index, predicat, count);
7469+ if( foundNode )
7470+ return foundNode;
7471+ } else if(predicat(p)) {
74507472 count++;
7451- if(count == index) {
7452- if( !foundNode )
7453- foundNode = p;
7454- break;
7473+ if(index == -1 || count == index) {
7474+ if( !foundNode )
7475+ foundNode = p;
7476+ return foundNode;
7477+ }
74557478 }
74567479 }
7457- return foundNode ;
7480+ return NULL ;
74587481}
74597482
74607483/// create xpointer from relative pointer string
7461- ldomXPointer ldomDocument::createXPointer ( ldomNode * baseNode, const lString16 & xPointerStr )
7484+ ldomXPointer ldomDocument::createXPointerV1 ( ldomNode * baseNode, const lString16 & xPointerStr )
74627485{
74637486 //CRLog::trace( "ldomDocument::createXPointer(%s)", UnicodeToUtf8(xPointerStr).c_str() );
74647487 if ( xPointerStr.empty() || !baseNode )
@@ -7535,14 +7558,86 @@ ldomXPointer ldomDocument::createXPointer( ldomNode * baseNode, const lString16
75357558 break;
75367559 case xpath_step_nodeindex:
75377560 // node index /N/
7561+ if ( index<=0 || index>(int)currNode->getChildCount() )
7562+ return ldomXPointer(); // node not found: invalid index
7563+ currNode = currNode->getChildNode( index-1 );
7564+ break;
7565+ case xpath_step_point:
7566+ // point index .N
7567+ if (*str)
7568+ return ldomXPointer(); // not at end of string
7569+ if ( currNode->isElement() ) {
7570+ // element point
7571+ if ( index<0 || index>(int)currNode->getChildCount() )
7572+ return ldomXPointer();
7573+ return ldomXPointer(currNode, index);
7574+ } else {
7575+ // text point
7576+ if ( index<0 || index>(int)currNode->getText().length() )
7577+ return ldomXPointer();
7578+ return ldomXPointer(currNode, index);
7579+ }
7580+ break;
7581+ }
7582+ }
7583+ return ldomXPointer( currNode, -1 ); // XPath: index==-1
7584+ }
7585+
7586+ ldomXPointer ldomDocument::createXPointerV2( ldomNode * baseNode, const lString16 & xPointerStr )
7587+ {
7588+ //CRLog::trace( "ldomDocument::createXPointer(%s)", UnicodeToUtf8(xPointerStr).c_str() );
7589+ if ( xPointerStr.empty() || !baseNode )
7590+ return ldomXPointer();
7591+ const lChar16 * str = xPointerStr.c_str();
7592+ int index = -1;
7593+ int count;
7594+ ldomNode * currNode = baseNode;
7595+ ldomNode * foundNode;
7596+ lString16 name;
7597+ xpath_step_t step_type;
7598+
7599+ while ( *str ) {
7600+ //CRLog::trace( " %s", UnicodeToUtf8(lString16(str)).c_str() );
7601+ step_type = ParseXPathStep( str, name, index );
7602+ //CRLog::trace( " name=%s index=%d", UnicodeToUtf8(lString16(name)).c_str(), index );
7603+ switch (step_type ) {
7604+ case xpath_step_error:
7605+ // error
7606+ //CRLog::trace(" xpath_step_error");
7607+ return ldomXPointer();
7608+ case xpath_step_element:
7609+ // element of type 'name' with 'index' /elemname[N]/
75387610 {
7539- int count = 0;
7540- ldomNode * foundItem = getNodebyIndex(currNode, index, count);
7541- if ( foundItem == NULL )
7542- return ldomXPointer(); // node not found: invalid index
7543- currNode = foundItem;
7611+ ldomNodeIdPredicate predicat(getElementNameIndex( name.c_str() ));
7612+ count = 0;
7613+ foundNode = getNodebyIndex(currNode, index, predicat, count);
7614+ if (foundNode == NULL) {
7615+ //CRLog::trace(" Element %d is not found. foundCount=%d", id, foundCount);
7616+ return ldomXPointer(); // node not found
7617+ }
7618+ // found element node
7619+ currNode = foundNode;
7620+ lString16 nm = currNode->getNodeName();
7621+ CRLog::trace("%d -> %s", index, LCSTR(nm));
75447622 }
75457623 break;
7624+ case xpath_step_text:
7625+ //
7626+ count = 0;
7627+ foundNode = getNodebyIndex(currNode, index, isTextNode, count);
7628+
7629+ if ( foundNode==NULL )
7630+ return ldomXPointer(); // node not found
7631+ // found text node
7632+ currNode = foundNode;
7633+ break;
7634+ case xpath_step_nodeindex:
7635+ // node index /N/
7636+ foundNode = getNodebyIndex(currNode, index, notNull, count);
7637+ if ( foundNode == NULL )
7638+ return ldomXPointer(); // node not found: invalid index
7639+ currNode = foundNode;
7640+ break;
75467641 case xpath_step_point:
75477642 // point index .N
75487643 if (*str)
@@ -7595,7 +7690,7 @@ lString16 ldomNode::getXPathSegment()
75957690 return lString16::empty_str;
75967691}
75977692
7598- lString16 ldomXPointer::toStringUsingNames ()
7693+ lString16 ldomXPointer::toStringUsingNamesOld ()
75997694{
76007695 lString16 path;
76017696 if ( isNull() )
@@ -7653,22 +7748,67 @@ lString16 ldomXPointer::toStringUsingNames()
76537748 return path;
76547749}
76557750
7656- static int getNodeIndex(ldomNode* parent, ldomNode *targetNode, int& count)
7751+ template<typename T>
7752+ static int getElementIndex(ldomNode* parent, ldomNode *targetNode, T predicat, int& count)
76577753{
76587754 for ( int i=0; i<parent->getChildCount(); i++ ) {
76597755 ldomNode * node = parent->getChildNode( i );
76607756 if( isBoxingNode(node) && targetNode != node ) {
7661- int index = getNodeIndex (node, targetNode, count);
7757+ int index = getElementIndex (node, targetNode, predicat , count);
76627758 if(index > 0)
76637759 return index;
7664- } else
7760+ } else if (predicat(node))
76657761 count++;
76667762 if ( node==targetNode )
76677763 return count;
76687764 }
76697765 return -1;
76707766}
76717767
7768+ lString16 ldomXPointer::toStringUsingNames()
7769+ {
7770+ lString16 path;
7771+ if ( isNull() )
7772+ return path;
7773+ ldomNode * node = getNode();
7774+ int offset = getOffset();
7775+ if ( offset >= 0 ) {
7776+ path << "." << fmt::decimal(offset);
7777+ }
7778+ ldomNode * p = node;
7779+ ldomNode * mainNode = node->getDocument()->getRootNode();
7780+ while (p && p!=mainNode) {
7781+ ldomNode * parent = p->getParentNode();
7782+ while( isBoxingNode(parent) )
7783+ parent = parent->getParentNode();
7784+ if ( p->isElement() ) {
7785+ // element
7786+ lString16 name = p->getNodeName();
7787+ if ( !parent )
7788+ return "/" + name + path;
7789+ int count = 0;
7790+ ldomNodeIdPredicate predicat(p->getNodeId());
7791+ int index = getElementIndex(parent, p, predicat, count);
7792+ if ( count>1 )
7793+ path = cs16("/") + name + "[" + fmt::decimal(index) + "]" + path;
7794+ else
7795+ path = cs16("/") + name + path;
7796+ } else {
7797+ // text
7798+ if ( !parent )
7799+ return cs16("/text()") + path;
7800+ int count = 0;
7801+ int index = getElementIndex(parent, p, isTextNode, count);
7802+ if ( count>1 )
7803+ path = cs16("/text()") + "[" + fmt::decimal(index) + "]" + path;
7804+ else
7805+ path = "/text()" + path;
7806+ }
7807+ p = parent;
7808+ }
7809+ return path;
7810+ }
7811+
76727812lString16 ldomXPointer::toStringUsingIndexes()
76737813{
76747814 lString16 path;
@@ -7689,7 +7829,7 @@ lString16 ldomXPointer::toStringUsingIndexes()
76897829 parent = parent->getParentNode();
76907830
76917831 int count = 0;
7692- int index = getNodeIndex (parent, p, count);
7832+ int index = getElementIndex (parent, p, notNull , count);
76937833
76947834 if( index>0 ) {
76957835 path = cs16("/") + fmt::decimal(index) + path;
0 commit comments