You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-users@xerces.apache.org by Boris Kolpackov <bo...@codesynthesis.com> on 2009/09/03 09:33:01 UTC

Re: XPath from DOMNode ?

Hi Ben,

Ben Griffin <be...@redsnapper.net> writes:

> Given a specific DOMNode, is there a method for finding (or deriving) a 
> valid XPath that uniquely identifies that DOMNode?

You could go up the document tree (by calling getParentNode) and construct
the XPath path by prefixing the element names, something along these
lines (pseudo-code):

string xpath (DOMElement* n)
{
  if (n == 0)
    return "/";
  else
    return xpath (n->getParentNode ()) + "/" + n->getName ();
}

This will work for documents that don't contain sequences of elements
on the same lavel. If you have to handle this situation then you will
need to extend this logic to also include the element indexes, e.g.,
//foo/bar[2].

Boris

-- 
Boris Kolpackov, Code Synthesis Tools  http://codesynthesis.com/~boris/blog
Open-source XML data binding for C++:  http://codesynthesis.com/products/xsd
XML data binding for embedded systems: http://codesynthesis.com/products/xsde

Re: XPath from DOMNode ?

Posted by Ben Griffin <be...@redsnapper.net>.
Boris thanks for that.
I came to a similar conclusion, which manages the element indices.
Not particularly rocket science - but here it is to share...

I found that basic_ostringstream<XMLCh> doesn't seem to deal well with  
single XMLCh characters or unsigned int, so I wrapped all of those up  
in XMLCh[]

basic_string<XMLCh> Parser::xpath(const DOMNode* startnode) {
	basic_string<XMLCh> xpath;
	if (startnode != NULL) {
		basic_ostringstream<XMLCh> osd;
		XMLCh sibch[8];					//For number conversion.
		const XMLCh sls[]= {'/',chNull};		// "/"
		const XMLCh bkt[]= {'(',')',chNull};	// "()"
		const XMLCh osq[]= {'[',chNull};		// "["
		const XMLCh csq[]= {']',chNull};		// "]"
		vector<basic_string<XMLCh> > bits;
		const DOMNode* n = startnode;
		while ( n != NULL ) {
			basic_ostringstream<XMLCh> oss;
			basic_string<XMLCh> name = n->getNodeName();
			if (name[0] == '#' && n->getNodeType() != DOMNode::DOCUMENT_NODE ) {
					name.erase(0,1); //remove the hash.
					oss << sls << name << bkt;
			} else {
				//This is v.slow for travelling through DOMText - will loop  
through each char.
				unsigned long sibnum = 1;
				const xercesc::DOMNode* s = n->getPreviousSibling();
				while ( s != NULL) {
					if (!name.compare(s->getNodeName())) { sibnum++ ;}
					s = s->getPreviousSibling();
				}
				XMLString::binToText(sibnum,sibch,7,10);
				oss << sls << name << osq << sibch << csq;
			}
			n = n->getParentNode();
			bits.push_back(oss.str());
		}
		while (bits.size() > 0) {
			xpath.append(bits.back());
			bits.pop_back();
		}
	}
	return xpath;
}


Best regards
	Ben.

On 3 Sep 2009, at 08:33, Boris Kolpackov wrote:

> Hi Ben,
>
> Ben Griffin <be...@redsnapper.net> writes:
>
>> Given a specific DOMNode, is there a method for finding (or  
>> deriving) a
>> valid XPath that uniquely identifies that DOMNode?
>
> You could go up the document tree (by calling getParentNode) and  
> construct
> the XPath path by prefixing the element names, something along these
> lines (pseudo-code):
>
> string xpath (DOMElement* n)
> {
>  if (n == 0)
>    return "/";
>  else
>    return xpath (n->getParentNode ()) + "/" + n->getName ();
> }
>
> This will work for documents that don't contain sequences of elements
> on the same lavel. If you have to handle this situation then you will
> need to extend this logic to also include the element indexes, e.g.,
> //foo/bar[2].
>
> Boris
>
> -- 
> Boris Kolpackov, Code Synthesis Tools  http://codesynthesis.com/~boris/blog
> Open-source XML data binding for C++:  http://codesynthesis.com/products/xsd
> XML data binding for embedded systems: http://codesynthesis.com/products/xsde