You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-users@xalan.apache.org by Indrajit Bhattacharya <in...@rediffmail.com> on 2007/06/05 12:31:31 UTC

Re: Re: Extra functions to XPath

Hi Dave,

I want to achieve the following:

I have a XercesDOM document object. There is an XPath expression like the following, for
, say, one attribute's value: cube(id('id1')). Here, id() is the XPath function, id1 is the id of an element
whose value is, say, 10. Cube is a function that I want to implement. I have to get the result 1000
when this XPath expression is evaluated. 

Please note that I should not have to have any XSL file. Everything has to be done in-memory.
Also, I need not do any transform on the input document. Only what I need to do is get the XPath
expression evaluated to get the correct value.

I have the following code. It returns correct value for id('id1'), but for cube(id('id1')) it throws 
xalanc::XPathParserException exception.

I will be grateful if you could please let me know where I am doing stuffs
wrong, and how to do it correctly to get the desired output.

Code:

XALAN_USING_XERCES(XMLPlatformUtils)
		XALAN_USING_XERCES(XMLException)
	XALAN_USING_XALAN(Function)
	XALAN_USING_XALAN(XalanTransformer)
     XALAN_USING_XALAN(XalanDOMString)
     XALAN_USING_XALAN(XalanDocument)
     XALAN_USING_XALAN(XalanElement)
     XALAN_USING_XALAN(XalanNode)
     XALAN_USING_XALAN(XercesDOMSupport)
     XALAN_USING_XALAN(XercesParserLiaison)
     XALAN_USING_XALAN(XPathEvaluator)
     XALAN_USING_XALAN(ElementPrefixResolverProxy)
     XALAN_USING_XALAN(XercesDocumentWrapper)
	 XALAN_USING_XALAN(XObjectPtr)
	 XALAN_USING_XALAN(XPathExecutionContext)
	 XALAN_USING_XALAN(MemoryManagerType)
	 XALAN_USING_XALAN(XalanCopyConstruct)

class FunctionCube : public Function
{
public:

	
	virtual XObjectPtr
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			const XObjectArgVectorType&		args,
			const LocatorType*				locator) const
	{
		if (args.size() != 1)
		{
            XPathExecutionContext::GetAndReleaseCachedString	theGuard(executionContext);

			executionContext.error(getError(theGuard.get()), context, locator);
		}

		assert(args[0].null() == false);	

#if defined(XALAN_STRICT_ANSI_HEADERS)
		using std::pow;
#endif

		return executionContext.getXObjectFactory().createNumber(pow(args[0]->num(), 3));
	}

#if !defined(XALAN_NO_USING_DECLARATION)
	using Function::execute;
#endif

	
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionCube*
#endif
	clone(MemoryManagerType&    theManager) const
	{
	    return XalanCopyConstruct(theManager, *this);
	}

protected:

	
	const XalanDOMString&
	getError(XalanDOMString&    theResult) const
	{
        theResult.assign("The cube() function accepts one argument!");

		return theResult;
	}

private:

	// Not implemented...
	FunctionCube&
	operator=(const FunctionCube&);

	bool
	operator==(const FunctionCube&) const;
};

int foo(xercesc::DOMDocument *dom_document_, char* xpath, std::string& output)
{
	
	 XMLPlatformUtils::Initialize();
	 XalanTransformer::initialize();
	 XPathEvaluator::initialize();

	
			{
				// Create a XalanTransformer.
				XalanTransformer	theXalanTransformer;

				const XalanDOMString	theNamespace(" ");

				
				theXalanTransformer.installExternalFunction(
					theNamespace,
					XalanDOMString("cube"),
					FunctionCube());

     				XercesDOMSupport      theDOMSupport;
				XercesParserLiaison   theParserLiaison(theDOMSupport);

     				XalanDocument*  theDocument =
		            theParserLiaison.createDocument(
               		   dom_document_,
		                  true,
            		      true,
		                  true);

			     XPathEvaluator  theEvaluator;

			     const XalanElement* const   theRootElement =
			     theDocument->getDocumentElement();	

			     ElementPrefixResolverProxy thePrefixResolver(theRootElement);

			     XalanNode* const  theNode =
				theEvaluator.selectSingleNode(
			             theDOMSupport,
			             theDocument,
					XalanDOMString("/").c_str(),
				    thePrefixResolver);
				 if(!theNode)
					 return 1;

	 			try
				 {
					 XalanDOMString str(xpath);
					const xalanc::XObjectPtr	theResult(
					theEvaluator.evaluate(
							theDOMSupport,
							theNode,
							XalanDOMString(str).c_str()));
			
					xalanc::XalanVector<char> charData1;
					string rtnStr1;
					theResult->str().transcode(charData1);
					rtnStr1.assign(charData1.begin(), charData1.end());
					output = rtnStr1; //put the result in output param
				}
				 catch(const xalanc::XPathParserException& e)
				 {
					 const xalanc::XalanDOMChar* ch = e.getType() ;
					 char* ch1 = (char*)ch;
						 
	 			 }

		
			}

	 XPathEvaluator::terminate();
	 XalanTransformer::terminate();
       XMLPlatformUtils::Terminate();

	return 0;
}  


On Tue, 20 Feb 2007 David Bertoni wrote :
>Indrajit Bhattacharya wrote:
>>Dave,
>>
>>Yes. But I see it uses .xsl file as input to the transform() function. Is there any other way of doing it without using .xsl and any other file ?
>>
>>Thanks for your reply.
>>
>>-Indrajit
>>
>>
>>
>>
>>On Tue, 20 Feb 2007 David Bertoni wrote :
>>  >Indrajit Bhattacharya wrote:
>>  >>Hi,
>>  >>
>>  >>I have a query on XPath:
>>  >>
>>  >>Is it possible to add extra functions to XPath 1.0 specifications, such that Xalan could
>>  >>call those functions actually implemented by me in my application, without using XSL ?
>
>If you install the function as the sample shows, it will be available in the XPathEvaluator from your XPath expressions.
>
>Dave

Re: Extra functions to XPath

Posted by David Bertoni <db...@apache.org>.
Indrajit Bhattacharya wrote:
> Hi Dave,
> 
> I want to achieve the following:
> 
> I have a XercesDOM document object. There is an XPath expression like 
> the following, for
> , say, one attribute's value: cube(id('id1')). Here, id() is the XPath 
> function, id1 is the id of an element
> whose value is, say, 10. Cube is a function that I want to implement. I 
> have to get the result 1000
> when this XPath expression is evaluated.
> 
> Please note that I should not have to have any XSL file. Everything has 
> to be done in-memory.
> Also, I need not do any transform on the input document. Only what I 
> need to do is get the XPath
> expression evaluated to get the correct value.
> 
> I have the following code. It returns correct value for id('id1'), but 
> for cube(id('id1')) it throws
> xalanc::XPathParserException exception.

Yes, because XPath does not define a function called cube.  You need to map 
your function's namespace to a particular prefix, and use that in the XPath 
expression.  You can see how this works by looking at the stylesheet for 
the sample you've copied.

> 
> I will be grateful if you could please let me know where I am doing stuffs
> wrong, and how to do it correctly to get the desired output.
> 
> Code:
>

...

...

> 
> int foo(xercesc::DOMDocument *dom_document_, char* xpath, std::string& 
> output)
> {
>      
>       XMLPlatformUtils::Initialize();
>       XalanTransformer::initialize();
>       XPathEvaluator::initialize();
> 
>      
>                {
>                     // Create a XalanTransformer.
>                     XalanTransformer     theXalanTransformer;
> 
>                     const XalanDOMString     theNamespace(" ");

A space is not a legal namespace URI.  It might work, but it might not. 
You should choose a better URI.

> 
>                     
>                     theXalanTransformer.installExternalFunction(
>                          theNamespace,
>                          XalanDOMString("cube"),
>                          FunctionCube());
> 
>                         XercesDOMSupport      theDOMSupport;
>                     XercesParserLiaison  theParserLiaison(theDOMSupport);
> 
>                         XalanDocument*  theDocument =
>                       theParserLiaison.createDocument(
>                           dom_document_,
>                             true,
>                             true,
>                             true);
> 
>                    XPathEvaluator  theEvaluator;
> 
>                    const XalanElement* const  theRootElement =
>                    theDocument->getDocumentElement();     
> 
>                    ElementPrefixResolverProxy 
> thePrefixResolver(theRootElement);

An element prefix resolver will not work, because you need to associate a 
prefix for the cube function with the namespace you used when you installed 
the extension function.  You will need to write your own PrefixResolver 
implementation that can resolve the prefix you've chosen to the correct 
namespace URI, or, if it can't, pass the request on to another PrefixResolver.

Dave