Add custom functions to XPath

xiaoxiao2021-03-06  64

Summary: Prajakta Joshi discusses how to create custom functions for XPath using the System.xml API in the .NET Framework SDK. The subject involves adding extended functions to XPath 1.0, looking forward to XPath 2.0 and extension functions in XSLT. (Page Page Page) In XML and XSL public newsgroups, requests for extended functions are a topic discussed. The motivation to write this article is because I noticed that there is a lot of user posts involving this topic. Xpath 1.0's XPath expression can return one of the following four basic XPath data types: * String * Numeric * Boolean * Node Set XSLT variable introduces an additional type in the expression language - Result Tree Fragment (Results) ). The core function library in XPath provides several basic tools for operating the XPath data type. Throughout these functions, you will find that this is not a comprehensive collection that meets 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 () , False (), LANG () NuMBer (), SUM (), Floor (), CEILING (), Round (), CEILT 1.0 (), Key (), Format-Number (), CURRENT (), Unparsed-entity-uri (), generate-id (), system-protety () requires non-XPath data types (for example, date) or XML development with powerful / custom data operation with XPath data type Personnel usually require additional functions. This article is intended to overview How to use System.xml in the Microsoft .NET Framework SDK to implement custom functions for XPath. Two strings are comparison when writing my first XPath query, I need to perform a comparison of uncomment to both strings.

The books.xml I have written as follows: Harry Potter and the GOBLET OF FIRE </ TITLE > <Author> <first-name> Mary </ first-name> <last-name> gradpre </ last-name> </ author> <my: price> 8.99 </ my: price> </ book> <book Style = "Young fiction"> <title> Lord of the rings </ title> <respect000> <first-name> j. </ first-name> <last-name> Tolkien </ last-name> </ author> <my: price> 22.50 </ my: price> </ book> </ bookstore> I am looking for a function similar to string.compare () in a string function. The closest function available in my solution is translate ().</p> <p>I solved this problem using the XPath class in system.xml.xpath namespace by the following code snippet: use system; use system.xml; use 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(.,'abcdefghijklmnopqrstuvwxyz ',' ABCDEFGHIJKLMNOPQRSTUVWXYZ ') ​​=' HARRY POTTER AND THE GOBLET OF FIRE ']"); XPathNodeIterator iterator = nav.Select (expr); // Iterate through selected Nodes. While ("Book Title: {0}", Iterator.current.Value);}}} This code generates the following output: Book Title: Harry Potter and the GOBLET OF Fire Although this solution is a bit long, I still solve my problem. When writing XPath queries for a few days, I want to remove string into an array of sub-strings in locations that match the definition of regular expressions. <? XML Version = "1.0" Encoding = "UTF-8"?> <books> <book> <title> Stephen Hawking's universes: The cosmos explained </ title> <authors> David Filkin, Stephen Hawking </ authors> < / Book> <book> <title> Writing Secure code </ title> <authors> Michael Howard, David Leblanc </ authors> </ book> </ books> I want to find out from the comma-separated list of <authors> elements Name of the Nth author's name - a bit of a bit of a string operation problem. I think this is a good opportunity to learn how to implement XPath custom extension functions. Implementation of Extended Functions in XPath I found that XPath 1.0 is not recommended to define mechanisms for extended function. But the good news is, I can provide a custom execution context for the XPath processor to parse the user-defined functions and variables in the XPath expression.</p> <p>The figure below explains the role of the xsltcontext class, the IxSltconTextFunction interface, and the IXSLTCONTEXTVARIA interface in my solution. Figure 1. Key Steps in the Role Solution of XSLTCONText 1.xPatHexPression.SetContext (CustomContext) provides an XPath processor (XPathnavigator), which has custom contexts for parsing user-defined functions and variables. CustomContext implements two key ways: resolvefunction () and resolvevariable () and resolvevariable (). 2. When Xpathnavigator encounters user-defined functions in the XPATHEXPRESSION, it is called the resolvefunction () method for custom context. ResolveFunction () Returns the appropriate custom function derived from IXSLTCONTextFunction. 3.XPathnavigator Call the invoke () method for this custom function at runtime. 4. When Xpathnavigator detects user-defined variables in XPATHEXPRESSION, it is called the resolvevariable () method for custom context. Resolvevariable () Returns the appropriate custom variable derived from IXSLTCONTEXTVARIABLE. 5. Xpathnavigator calls the evAate () method for this custom variable at runtime. I decided to write a custom XPath function-split () so that the function of the function is similar to the regex.split () method in the .NET SDK. Here is how to combine all of these code snippets. The role of the XSLTContext class first, I implemented my custom xsltContext to provide the XPath processor to provide information on resolving user-defined functions. ResolveFunction and ResolveVariable are two key ways to the XSLTContext class, and users must override them to implement custom parsing. These methods are called by XPathnavigator during runtime to resolve references to user-defined functions and variables in XPath query expressions. Note that I encapsulated a resolvevariable object in the CustomContext class. This object is a container for variables in the XPath expression.</p> <p>public class CustomContext: XsltContext {// XsltArgumentList to store my user defined variables private XsltArgumentList m_ArgList; // Constructors public CustomContext () {} public CustomContext (NameTable nt): base (nt) {} public CustomContext (NameTable nt, XsltArgumentList argList) :.. base (nt) {m_ArgList = argList;} // Returns the XsltArgumentList that contains custom variable definitions public XsltArgumentList argList {get {return m_ArgList;}} // Function to resolve references to my custom functions public override IXsltContextFunction 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;</p> <p>} // Function to resolve references to my custom variables public override IXsltContextVariable 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 the next step is to achieve the role of interfaces for CustomContext The IXSLTCONTEXTFUNCTION interface used by the class. The invoke () method of this object is called by the XPathnavigator using the provided parameters at runtime.</p> <p>public class XPathRegExExtensionFunction: IXsltContextFunction {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 m_ReturnType;}} // Constructor public XPathRegExExtensionFunction (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 t o execute the user defined function public object Invoke (XsltContext xsltContext, 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 =</p> <p>R.Replace (Args [0] .tostring (), args [2] .tostring ()); str = s2; break;}}}}}}}}}}}}} The role XPath expression of the IXSLTCONTEXTVARIABLE interface can contain user-defined Variables reference, for example: xpatHexpression expr1 = nav.compile ("MyFunctions: split (string (.), ',', $ Var)"); I need to implement the IXSLTCONTEXTVARIABLE interface and override the evAlate () method (this method is running when public class XPathExtensionVariable: IXsltContextVariable {// 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 (XsltContext xsltContext) {XsltArgumentList vars = ((CustomContext) xsltContext) .ArgList; return vars.GetParam (m_VarName, null);}. public bool isLocal {get {return false;}} public bool IsParam { Get {returnaf false; }}} Public xpathResultType VariableType {get {return xpathresulttype.Any;}}} Merge code together, I use the XPATHEXPRESSION.SETCONTEXT () method to incorporate it into my custom context object. Figure 1 summarizes all the steps in the solution. Note that the XSLTContext class is inherited from XMLNameSpaceManager and adds my custom namespace by using AddNameSpace () to the collection.</p> <p>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 XsltArgumentList XsltArgumentList varList = new XsltArgumentList (); 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 XsltContext 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 will generate the following output:</p></div><div class="text-center mt-3 text-grey"> 转载请注明原文地址:https://www.9cbs.com/read-90885.html</div><div class="plugin d-flex justify-content-center mt-3"></div><hr><div class="row"><div class="col-lg-12 text-muted mt-2"><i class="icon-tags mr-2"></i><span class="badge border border-secondary mr-2"><h2 class="h6 mb-0 small"><a class="text-secondary" href="tag-2.html">9cbs</a></h2></span></div></div></div></div><div class="card card-postlist border-white shadow"><div class="card-body"><div class="card-title"><div class="d-flex justify-content-between"><div><b>New Post</b>(<span class="posts">0</span>) </div><div></div></div></div><ul class="postlist list-unstyled"> </ul></div></div><div class="d-none threadlist"><input type="checkbox" name="modtid" value="90885" checked /></div></div></div></div></div><footer class="text-muted small bg-dark py-4 mt-3" id="footer"><div class="container"><div class="row"><div class="col">CopyRight © 2020 All Rights Reserved </div><div class="col text-right">Processed: <b>0.042</b>, SQL: <b>9</b></div></div></div></footer><script src="./lang/en-us/lang.js?2.2.0"></script><script src="view/js/jquery.min.js?2.2.0"></script><script src="view/js/popper.min.js?2.2.0"></script><script src="view/js/bootstrap.min.js?2.2.0"></script><script src="view/js/xiuno.js?2.2.0"></script><script src="view/js/bootstrap-plugin.js?2.2.0"></script><script src="view/js/async.min.js?2.2.0"></script><script src="view/js/form.js?2.2.0"></script><script> var debug = DEBUG = 0; var url_rewrite_on = 1; var url_path = './'; var forumarr = {"1":"Tech"}; var fid = 1; var uid = 0; var gid = 0; xn.options.water_image_url = 'view/img/water-small.png'; </script><script src="view/js/wellcms.js?2.2.0"></script><a class="scroll-to-top rounded" href="javascript:void(0);"><i class="icon-angle-up"></i></a><a class="scroll-to-bottom rounded" href="javascript:void(0);" style="display: inline;"><i class="icon-angle-down"></i></a></body></html><script> var forum_url = 'list-1.html'; var safe_token = 'Kx3zXbj5IXu4pGjJVLGFxGOXz_2FM_2BVsneMTmMZByxBJ2d071DZKniEW9I1cHCihnPWN80rcoOSvzJUhEYjrS_2BHQ_3D_3D'; var body = $('body'); body.on('submit', '#form', function() { var jthis = $(this); var jsubmit = jthis.find('#submit'); jthis.reset(); jsubmit.button('loading'); var postdata = jthis.serializeObject(); $.xpost(jthis.attr('action'), postdata, function(code, message) { if(code == 0) { location.reload(); } else { $.alert(message); jsubmit.button('reset'); } }); return false; }); function resize_image() { var jmessagelist = $('div.message'); var first_width = jmessagelist.width(); jmessagelist.each(function() { var jdiv = $(this); var maxwidth = jdiv.attr('isfirst') ? first_width : jdiv.width(); var jmessage_width = Math.min(jdiv.width(), maxwidth); jdiv.find('img, embed, iframe, video').each(function() { var jimg = $(this); var img_width = this.org_width; var img_height = this.org_height; if(!img_width) { var img_width = jimg.attr('width'); var img_height = jimg.attr('height'); this.org_width = img_width; this.org_height = img_height; } if(img_width > jmessage_width) { if(this.tagName == 'IMG') { jimg.width(jmessage_width); jimg.css('height', 'auto'); jimg.css('cursor', 'pointer'); jimg.on('click', function() { }); } else { jimg.width(jmessage_width); var height = (img_height / img_width) * jimg.width(); jimg.height(height); } } }); }); } function resize_table() { $('div.message').each(function() { var jdiv = $(this); jdiv.find('table').addClass('table').wrap('<div class="table-responsive"></div>'); }); } $(function() { resize_image(); resize_table(); $(window).on('resize', resize_image); }); var jmessage = $('#message'); jmessage.on('focus', function() {if(jmessage.t) { clearTimeout(jmessage.t); jmessage.t = null; } jmessage.css('height', '6rem'); }); jmessage.on('blur', function() {jmessage.t = setTimeout(function() { jmessage.css('height', '2.5rem');}, 1000); }); $('#nav li[data-active="fid-1"]').addClass('active'); </script>