Reprinted: Add a UDF to xpath

Source: Internet
Author: User
Tags xsl xslt

InWebApplicationProgramTwo methods for processing database updates in

Microsoft Corporation

Prajakta Joshi

October 8, 2002

Abstract:The special writer prajakta Joshi discusses how to use the system. xml API in the. NET Framework SDK to create custom functions for xpath. The topic involves adding extension functions to XPath 1.0, looking forward to XPath 2.0, and using extension functions in XSLT. (14 page printing)


In XML and XSL public newsgroupsExtended FunctionsThe request is a topic that is frequently discussed. The motivation for writing this article is that I have noticed that a large number of user posts are related to this topic. The XPath expression in XPath 1.0 can return one of the following four basic XPath data types:

String

Value

Boolean Value

Node Set

The XSLT variable introduces an additional type-result tree fragment (result tree fragment) to the expression language ).

The core function library in XPath and several other XSLT-specific additional functions provide several basic tools for operating the XPath data type. Looking at these functions, you will find that this is not a complete set that can meet the needs of all users.

XPath type Function

Node Set

Last (), position (), count (), ID (), local-Name (), namespace-Uri (), name ()

String

String (), Concat (), starts-with (), contains (), substring-before (), substring-after (), substring (), string-length (), normalize-space (), translate ()

Boolean Value

Boolean (), not (), true (), false (), Lang ()

Value

Number (), sum (), floor (), ceiling (), round ()

New functions in XSLT 1.0

Document (), key (), format-number (), current (), unparsed-entity-Uri (), generate-ID (), system-property ()

XML developers who need to operate non-XPath data types (such as dates) or execute powerful/custom data operations with XPath data types usually need additional functions. This document describes how to use the system. xmlapi in the Microsoft. NET Framework SDK to implement custom functions for xpath.

Back to Top


Comparison of two strings

When writing my first XPath query, I need to perform case-insensitive comparison on the two strings. My books. XML is as follows:

<Bookstore xmlns: My = "urn: http // mycompany.com/"> <book style =" Young Adult "> <title> Harry Potter and the Goblet of Fire </title> <author> <first-name> Mary </First-name> <last-name> gradpre </last-name> </author> <my: pricing> 8.99 </My: price> </book> <book style = "Young Fiction"> <title> Lord of the Rings </title> <author> <first-name> J. </first-name> <last-name> Tolkien </last-name> </author> <my: price> 22.50 </My: price> </book> </bookstore>

I found a function similar to string. Compare () in the XPath 1.0 string function. The closest function available in my solution is translate (). I use the followingCodeFragment uses the XPath class in the system. xml. XPath namespace to solve this problem:

Using system; using system. XML; using system. XML. XPath; public class sample {public static void main (string [] ARGs) {// load source XML into xpathdocument. xpathdocument XD = new xpathdocument (ARGs [0], xmlspace. preserve); // create xpathnavigator from xpathdocument. xpathnavigator nav = XD. createnavigator (); xpathexpression expr; expr = nav. compile ("/bookstore/book/title [translate (., 'abcdefghijklmnopqrstuvwxy', 'abcdefghijklmnopqrstuvwxy') = 'Harry Potter and the goblet of fire'] "); xpathnodeiterator iterator = nav. select (expr); // iterate through selected nodes. while (iterator. movenext () {console. writeline ("book title: {0}", iterator. current. value );}}}

This code generates the following output results:

 
Book title: Harry Potter and the Goblet of Fire

Although this solution is a bit long, I still solve my problem. When writing an XPATH query several days later, I want to split the string into an array of substrings at the position defined by the regular expression matching.

<? XML version = "1.0" encoding = "UTF-8"?> <Books> <book> <title> Stephen Hawking's universe: the cosmos explained </title> <authors> David filkin, stephen Hawking </authors> </book> <title> writing Secure Code </title> <authors> Michael Howard, david lebalanc </authors> </book> </books>

I want<Authors>Find the name of the nth author in the comma-separated list of elements-a complicated string operation problem. I think this is a good opportunity to learn how to implement XPath udfs.

ImplementationXpathExtended functions in

I found that the extension function definition mechanism is not recommended for xpath 1.0. But the good news is that I can provide a custom execution context for the XPath processor to parse user-defined functions and variables in the XPath expressions.

Explained in the namespace of system. xml. XSL in my solutionXsltcontextClass,IxsltcontextfunctionInterfaces andIxsltcontextvariableInterface role.

Figure1. effectcontextRole

Key steps in the solution

1.Xpathexpression. setcontext (customcontext)Provides an XPATH processor (XpathnavigatorIs used to parse user-defined functions and variables.Customcontext(From abstract classXsltcontextTo implement two key methods:Resolvefunction ()AndResolvevariable ().

2. When xpathnavigatorXpathexpressionWhen a user-defined function is encountered, it callsResolvefunction ()Method.Resolvefunction ()Return fromIxsltcontextfunctionDerived udfs.

3.XpathnavigatorUse the provided parameters to call the custom function at runtime.Invoke ()Method.

4. WhenXpathnavigatorInXpathexpressionWhen a user-defined variable is detected, it callsResolvevariable ()Method.Resolvevariable ()Return fromIxsltcontextvariableDerived custom variables.

5.XpathnavigatorCall this custom variable at runtimeEvaluate ()Method.

I decided to write a custom XPath function-Split ()So that the function behavior is similar to the RegEx. Split () method in. Net SDK. The following describes how to merge all these code snippets.

XsltcontextClass role

First, I implemented my customXsltcontextTo provide the XPath processor with the information needed to parse user-defined functions. ResolvefunctionAndResolvevariable isXsltcontextYou must override these two key methods to implement custom parsing. These methods areXpathnavigatorTo parse references to user-defined functions and variables in the XPath query expression.

Note thatCustomcontextClass encapsulates a resolvevariable object. This object is the container of the variable in the XPath expression.

Public class customcontext: extends tcontext {// your targumentlist to store my User Defined variables private extends targumentlist m_arglist; // constructors public customcontext () {} public customcontext (nametable NT): Base (NT) {} public customcontext (nametable nt, inclutargumentlist Arglist): Base (NT) {m_arglist = Arglist;} // returns the specified targumentlist that contains custom variable definitions. public writable targumentlist Arglist {get {return m_arglist ;}}// function to resolve references to my custom functions. public override imo-tcontextfunction resolvefunction (string prefix, string name, xpathresulttype [] argtypes) {xpathregexextensionfunction func = NULL; // create an instance of appropriate extension function class. switch (name) {Case "split": // usage // myfunctions: Split (string source, string regex_pattern, int N) returns string func = new xpathregexextensionfunction ("split ", 3, 3, new xpathresulttype [] {xpathresulttype. string, xpathresulttype. string, xpathresulttype. number}, xpathresulttype. string); break; Case "replace": // usage // myfunctions: Replace (string source, string regex_pattern, string replacement_string) returns string func = new xpathregexextensionfunction ("replace ", 3, 3, new xpathresulttype [] {xpathresulttype. string, xpathresulttype. string, xpathresulttype. string}, xpathresulttype. string); break;} return func;} // function to resolve references to my custom variables. public override imo-tcontextvariable resolvevariable (string prefix, string name) {// create an instance of an xpathextensionvariable. xpathextensionvariable var; Var = new xpathextensionvariable (name); Return var;} public override int comparedocument (string baseuri, string nextbaseuri) {return 0;} public override bool preservewhitespace (xpathnavigator node) {return true;} public override bool whitespace {get {return true ;}}}

Ixsltcontextfunction interface role

The next step is to implementCustomcontextClass used

Ixsltcontextfunction

Interface. The

Invoke ()

MethodXpathnavigatorCall with the provided parameters.

Public class xpathregexextensionfunction: extends {private xpathresulttype [] m_argtypes; private xpathresulttype m_returntype; private string m_functionname; private int m_minargs; private int m_maxargs; // methods to access the private fields. public int minargs {get {return m_minargs;} public int maxargs {get {return m_maxargs;} public xpathresulttype [] argtypes {get {return m_argtypes ;}} public xpathresulttype returntype {get {return region ;}// constructor public region (string name, int minargs, int maxargs, xpathresulttype [] argtypes, xpathresulttype returntype) {m_functionname = Name; m_minargs = minargs; m_maxargs = maxargs; m_argtypes = argtypes; m_returntype = returntype;} // This method is invoked at run time to execute the user defined function. public object invoke (effectcontext extends tcontext, object [] ARGs, xpathnavigator doccontext) {RegEx R; string STR = NULL; // The two custom XPath extension functions switch (m_functionname) {Case "split": r = new RegEx (ARGs [1]. tostring (); string [] S1 = R. split (ARGs [0]. tostring (); int n = convert. toint32 (ARGs [2]); If (s1.length <n) STR = ""; else STR = S1 [n-1]; break; Case "replace ": R = new RegEx (ARGs [1]. tostring (); string S2 = R. replace (ARGs [0]. tostring (), argS [2]. tostring (); STR = S2; break;} return (object) STR ;}}

IxsltcontextvariableInterface role

XPath expressions can contain user-defined variable references, for example:

 
Xpathexpression expr1 = nav. Compile ("myfunctions: Split (string (.), ',', $ var )");

I need to implement the ixsltcontextvariable interface and override the evaluate () method (this method is run

Public class xpathextensionvariable: ipolictcontextvariable {// The name of the User-Defined variable to resolve private string m_varname; Public xpathextensionvariable (string varname) {m_varname = varname ;} // This method is invoked at run time to find the value of the user defined variable. public object evaluate (extends tcontext) {extends targumentlist vars = (customcontext) extends tcontext ). arglist; return vars. getparam (m_varname, null);} public bool islocal {get {return false;} public bool isparam {get {return false;} public xpathresulttype variabletype {get {return xpathresulttype. any ;}}}

Merge Code together

Finally, I used the xpathexpression. setcontext () method to pass it into my custom context object. Figure 1 summarizes all the steps in the solution. Please note that,XsltcontextClasses are inherited from xmlnamespacemanager and my custom namespace is added to the set by using addnamespace.

Using system; using system. XML; using system. XML. XSL; using system. XML. XPath; using system. text. regularexpressions; public class sample {public static void main (string [] argc) {// load source XML into xpathdocument. xpathdocument Doc = new xpathdocument ("books. XML ", xmlspace. preserve); // create xpathnavigator from xpathdocument. xpathnavigator nav = Doc. createnavigator (); // Add User-Defined variable to the specified targumentlist. required targumentlist varlist = new required targumentlist (); varlist. addparam ("Var", "", 2); // compile the xpathexpression. // note that the compilation step only checks the query expression // for correct XPath syntax. // user defined functions and variables are not resolved. xpathexpression expr1 = nav. compile ("myfunctions: Split (string (.), ',', $ var) "); // create an instance of a custom tcontext object. customcontext cntxt = new customcontext (New nametable (), varlist); // Add a namespace definition for myfunctions prefix. cntxt. addnamespace ("myfunctions", "http: // myxpathextensionfunctions"); // associate the custom context with the xpathexpression object. expr1.setcontext (cntxt); xpathnodeiterator it = nav. select ("/books/book/authors"); While (it. movenext () {console. writeline ("Authors: {0}", it. current. value); console. writeline ("second author: {0}", it. current. evaluate (expr1 ));}}}

Run this code to generate the following output:

 
Authors: David filkin, Stephen hawkingsecond Author: Stephen hawkingauthors: Michael Howard, David leblancsecond Author: David Leblanc

Other usage of extended functions

After I discovered the mechanism of using extended functions, I used extended functions in many other data operations when programming with XPath. Some other situations include:

Operation Date:Comparing Two date strings is a common operation. To achieve this, I used the system. datetime. Compare () method.

Operation Value:Math method. Class provides a detailed set of methods for common mathematical operations. I willABS ()Method is used as a user-defined function.

Operation Date:Comparing Two date strings is a common operation. To achieve this, I used the system. datetime. Compare () method.

Operation string:The string class provides a detailed set of methods for common string operations. I foundToupper ()AndTolower ()Methods are useful when used as user-defined functions.

There are countless such cases. You can use any. Net class in your custom functions based on your actual situation.

Future Direction:Xpaths 2.0

Since W3C XML architecture data types are increasingly integrated with XPath 2.0, functions and operators of XQuery 1.0 and XPath 2.0 provide XML developers with a function library that is richer than functions currently present in XPath 1.0. This does not completely eliminate the need for user-defined functions in XPath 2.0. For powerful and scalable query languages of XML, the extension mechanism is indispensable.

XSLTExtended functions in

In XSLT 1.0, container transform implements the namespaceURN: Schemas-Microsoft-com: XSLTUsed as an extension namespace. It provides built-in support for <msxsl: node-set> extension functions and <msxsl: SCRIPT> extension elements.

In XSLT, You can implement user-defined functions in two ways:

1. style sheet script

2. Add extension objects to xsltargumentlist

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.