A simple tutorial on Web development using the XSLT API under Python _python

Source: Internet
Author: User
Tags soap prepare ranges static class xsl xslt wsdl in python

Kafka-style SOAP endpoints

The Kafka-xsl Soap Toolbox (see Resources) developed by Christopher Dix is an XSLT framework for constructing soap endpoints. It covers only SOAP 1.1, but the Kafka endpoint demonstrates the ability to pass the Userland soap validator (userland soap Validator) and it does not seem too difficult to update it according to SOAP 1.2. Listing 1 shows a sample Kafka endpoint: A SOAP server that asks for the sum of two (a typical and simple soap sample).

Listing 1. Kafka SOAP endpoints for the sum of two numbers

<?xml version= "1.0" encoding= "UTF-8"?> <xsl:stylesheet version= "1.0" xmlns:method= "http://www.topxml.com/" Xmlns:xsl= "Http://www.w3.org/1999/XSL/Transform" > <!--add.xsl:Kafka SOAP Endpoint Example, with modifications --> <!--Import soap.xsl to use the framework--> <xsl:import href= "kafka/soap.xsl"/> <xsl:output Method= "xml" encoding= "Utf-8" omit-xml-declaration= "yes"/> <!--Define The global variables for the framework--&G
  T <xsl:variable name= "method" >Add</xsl:variable> <xsl:variable name= "Methodns" >http:// Www.topxml.com/</xsl:variable> <!--Add:add two numbers and return the sum--> <!--Function Add (A A 
   s double, B as Double) as double--> <xsl:template name= "Processpayload" > <xsl:param name= "Payload"/> <xsl:for-each select= "$Payload" > <!--this are how to retrieve parameters from the input--> < Xsl:variable name= "A" select= "number" (A|method:a) "/> <xsl:variable name=" B "select=" number (b|method:b) "/> <!--the writeparameter template ta  Kes the qualified name for a response parameter as, as its value and a QName specifying the TPE (for the Xsi:type attribute)--> <xsl:call-template name= "Writeparameter" > <xsl:with-param name= "P" select= "' Result '"/> <xsl:with-param name= "V" select= "$A + $B"/> <xsl:with-param name= "T" select= "' Xsd:dou

 Ble ' "/> </xsl:call-template> </xsl:for-each> </xsl:template> </xsl:stylesheet>

The XSLT endpoint imports the SOAP framework (file kafka/soap.xsl), sets the parameters that the framework will use, and sets the template that it will assign when it processes the entire XML document that forms the SOAP message. Global variables method and Methodns Declare the XML element that makes up the message. After the SOAP envelope is processed, the framework calls the Processpayload template, which passes in the payload of the XML body. Xsl:for-each is the standard technique for switching contexts into desired nodes. Parameters A and B are read from this element using a simple xpaths, and the frame is called again to help write out the response parameters. The Writeparameter template lets you specify the element name, the data type, and the value of each output parameter. The response value in this example is the result of adding two input parameters.

Deploying this endpoint as a server is equivalent to setting up an HTTP listener. The Python basehttpserver module gives you the mechanism you need to handle the HTTP portions of the protocol with ease. See Listing 2.

Listing 2. The Python HTTP framework for the KAFKA SOAP endpoint implemented in Listing 1

#HTTP Listener code for SOAP Server import Basehttpserver #The processor class are the core of the XSLT API from Ft.Xml.Xs LT Import Processor #4XSLT uses a inputsource system for reading XML from ft.xml import inputsource = "add . Xsl class kafkasoaphandler (basehttpserver.basehttprequesthandler): Def init (CLS): From Ft.Lib import Uri #Set Up a processor instance to use Kafkasoaphandler.processor = Processor.processor () #Load it with add.xsl Add_ur i = Uri.ospathtouri (Soap_impl_file, attemptabsolute=1) transform = InputSource.DefaultFactory.fromUri (Add_uri) KAF
    KaSoapHandler.processor.appendStylesheet (Transform) #Now The processor is prepped with a transform and can used
  #over and over for the same transform return #Make init () A static method of the class init = Classmethod (init)
      def do_post (self): Clen = Self.headers.getheader (' content-length ') if Clen:clen = Int (clen) Else: print ' POST Error:misSing Content-length ' return if Self.path!= '/add ': Self.send_error (404) input_body = Self.rfile.read (
    Clen) #input_body is the request SOAP envelope and contents response_body = Self._run_through_kafka (input_body)
  #response_body is the response SOAP envelope and contents self._send_response ("OK", Response_body) return def _run_through_kafka (self, body): #In 4Suite all inputsources have base URIs into case they refer to #other URIs
    In some way and resolution are required. #The SOAP messages won't have any such URI references #So use a dummy base URI Source = Inputsource.defaultfac Tory.fromstring (Body, "urn:dummy") response = Self.processor.run (source) return response def _send_response (self , code, MSG, body): #Prepare A normal response self.send_response (' OK ') #Send standard HTP headers SE
Lf.send_header (' Content-type ', ' text/html charset=utf-8 ') self.send_header ("Connection", "close")    Self.send_header ("accept-ranges", "bytes") self.send_header (' Content-length ', Len (body)-1) self.end_headers () #Send the response prepared by the "SOAP End" Self.wfile.write (body) return listen_on_port = 8888 #Set u P to-run on the local machine server_address = (' 127.0.0.1 ', Listen_on_port) kafkasoaphandler.init () httpd = basehttpserver.ht Tpserver (server_address, Kafkasoaphandler) print "Listening on port" and Listen_on_port #Go into a The main event loop httpd.

 Serve_forever ()

We annotate the list in detail, so it should be easy to understand. Note that this code is very simple because it only needs to handle the HTTP portion of the protocol, and the work of the XML and SOAP portions is done to the KAFKA framework. The server is dedicated to one endpoint, so it only needs to parse and set the XSLT transformation once, and then it can simply repeatedly run the transformation for each new request. This is why the processor settings are migrated to a special class method, which is called immediately when the handler is registered to the server. The Classmethod built-in method is a new feature in Python 2.2, which is actually the version necessary for this example and later examples. It provides an implicit class object (CLS) that allows you to attach static data, such as a prepared processor instance, to the object, and then typically use it by reference to the self instance on the normal method.

We tested the endpoint with the latest release of Soappy 0.10.1 (see Resources), which has many great new features that we'll discuss later in this column. Listing 3 is the Soappy client that uses the endpoint. Open a command shell and run the Python listing2.py for the server. Then open another shell and run Python listing3.py, which will report the correct response, shaped like Add result:7.0.

Listing 3: Soappy Client for the sum of two numbers

Import soappy
ENDPOINT = "Http://localhost:8888/add"
Add_ns = "http://www.topxml.com/"
 
remote Soappy.soapproxy (ENDPOINT, Namespace=add_ns)
print "ADD result:", remote. ADD (A=3, b=4)

Use description

As we said earlier, not only is the payload in XML a useful Web service feature, it is also a useful feature. Listing 4 is a WSDL file for adding a service, which is based on Christopher Dix's original file modification. It is a version of WSDL 1.1.

Listing 4. WSDL for adding a service

<?xml version= "1.0" encoding= "UTF-8"?> <definitions name= "adder" targetnamespace= "http://www.topxml.com/" xmlns:tns= "http://www.topxml.com/" xmlns:xsd= "Http://www.w3.org/1999/XMLSchema" xmlns= "http://"  schemas.xmlsoap.org/wsdl/"> <message name=" Add "> <part name=" A "type=" xsd:double "/> <part-name=" B " Type= "xsd:double"/> </message> <message name= "Addresponse" > <part name= "param" type= "xsd:double"/ > </message> <porttype name= "Adder-port-type" > <operation name= "Add" > <input message= "tns:a DD "/> <output message=" Tns:addresponse "/> </operation> </portType> <binding name=" adder-s Oap-binding "type=" Tns:adder-port-type "xmlns:soap=" http://schemas.xmlsoap.org/wsdl/soap/"> <soap:binding TR Ansport= "Http://schemas.xmlsoap.org/soap/http" style= "rpc"/> <operation name= "Add" > <soap:operat Ion soapaction= "http://tempuri.org/"/> <input> <soap:body use= "encoded" namespace= http://www.topxml.com/"encodingstyle=" Http://schemas.xmlsoap.org/soa
     p/encoding/"/> </input> <output> <soap:body use=" encoded "namespace=" http://www.topxml.com/" encodingstyle= "http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> &LT;/BINDING&G
 T <service name= "Adder-service" > <port name= "adder-port" binding= "tns:adder-soap-binding" > <soap: Address location= "Http://127.0.0.1:8888/add" xmlns:soap= "http://schemas.xmlsoap.org/wsdl/soap/"/> </port

 > </service> </definitions>

Listing 5 provides an XSLT script that renders useful information for endpoint users. It is an adaptation of a transformation developed from the previous DeveloperWorks article "WSDL Processing with XSLT" (see Resources). It uses many free methods (liberty) and shortcuts (especially when it handles qualified names in the WSDL context), but it is also licensed for most WSDL 1.1 files currently in use.

Listing 5. XSLT Script

<?xml version= "1.0" encoding= "Utf-8"?> <xsl:stylesheet version= ' 1.0 ' xmlns:xsl= ' Http://www.w3.org/1999/XSL
 /transform "xmlns:wsdl=" http://schemas.xmlsoap.org/wsdl/"xmlns:soap=" http://schemas.xmlsoap.org/wsdl/soap/"> <xsl:output method= ' html '/> <!--Lookup tables for messages, porttypes, bindings and services--> <xsl:ke Y name= ' message ' match= ' wsdl:definitions/wsdl:message ' use= ' @name '/> <xsl:key ' name= port-type ' "Match=" Wsdl:de Finitions/wsdl:porttype "use= ' @name '/> <xsl:key name= ' binding ' match= ' wsdl:definitions/wsdl:binding" us E= ' @name '/> <xsl:key name= ' service ' match= ' wsdl:definitions/wsdl:service ' use= ' @name '/> <xsl:template Match= '/' >  

It is often convenient to provide a humanized WSDL description of the service on the host on which the WEB service itself resides. Listing 6 is a variant of Listing 2, which also completes this task. It actually offers three kinds of features:

    1. For GET requests on port 9000: provides an easy-to-understand description of the WEB service invocation message
    2. For GET requests on port 8888: provide an unhandled WSDL file
    3. For POST requests on port 8888: SOAP requests are executed.

Listing 6. Variant of Listing 2

#HTTP Listener code for SOAP Server import Basehttpserver #The processor class are the core of the XSLT API from Ft.Xml.Xs LT Import Processor #4XSLT uses a inputsource system for reading XML from ft.xml import inputsource = "add . xsl "wsdl_file =" listing4.xml "html_view_transform =" Listing5.xslt "Class Kafkasoaphandler ( Basehttpserver.basehttprequesthandler): Def init (CLS): From Ft.Lib import Uri #Set up a processor instance to us E cls.processor = processor.processor () #Load it with add.xsl Add_uri = Uri.ospathtouri (Soap_impl_file, attemp
    tabsolute=1) Transform = InputSource.DefaultFactory.fromUri (Add_uri) cls.processor.appendStylesheet (transform) #Now The processor is prepped with a transform and can are used #over and over for the same transform #Prep for WS DL Requests cls.wsdl = open (wsdl_file). Read () return #Make init () A static method of the class init = Classmet Hod (INIT) def do_post (self): Clen = Self.headeRs.getheader (' content-length ') if Clen:clen = Int (clen) else:print ' POST error:missing Content-leng Th ' return if Self.path!= '/add ': Self.send_error (404) Input_body = Self.rfile.read (Clen) #input_ The body is the request SOAP envelope and contents response_body = Self._run_through_kafka (input_body) #response_body is the response SOAP envelope and contents _send_response (self, k, ' OK ', response_body) return def do_get (self ): #response_body is the WSDL file _send_response (self,, ' OK ', self.wsdl) return def _RUN_THROUGH_KAF Ka (self, body): #In 4Suite all inputsources have base URIs in case they refer to #other URIs in some way and Resol
    Ution is required. #The SOAP messages won't have any such URI references #So use a dummy base URI Source = Inputsource.defaultfac Tory.fromstring (Body, "urn:dummy") response = Self.processor.run (source) Return response class Htmlhandler (Basehtt PServer.basehttprequesthandler): Def init (CLS): From Ft.Lib import Uri #Perform the transform once and store the
                    Result processor = Processor.processor () Html_desc_uri = Uri.ospathtouri (Html_view_transform, attemptabsolute=1) Transform = InputSource.DefaultFactory.fromUri (Html_desc_uri) Processor.appendstylesheet (transf ORM) Wsdl_uri = Uri.ospathtouri (wsdl_file, attemptabsolute=1) Source = InputSource.DefaultFactory.fromUri (Wsdl_uri Cls.html_desc = Processor.run (source) return #Make init () A static class method init = Classmethod (init) d EF Do_get (self): #response_body is the WSDL file _send_response (self, "OK", Self.html_desc) return #Turn _send_response into a global function #for sharing between the classes Def _send_response (handler, code, MSG, body): # Prepare a normal response Handler.send_response ("OK") #Send standard HTP headers (' Con Tent-type ', ' text/html;Charset=utf-8 ') handler.send_header ("Connection", "Close") Handler.send_header ("accept-ranges", "bytes") Handl Er.send_header (' Content-length ', Len (body)-1) handler.end_headers () #Send the "response prepared by the" SOAP End PO int Handler.wfile.write (body) return def soap_listener_function (): Listen_on_port = 8888 #Set up to run on L Ocal machine server_address = (' 127.0.0.1 ', Listen_on_port) kafkasoaphandler.init () httpd = Basehttpserver.httpserve R (server_address, Kafkasoaphandler) print "Listening for Get and POST on port", Listen_on_port #Go into a The main eve
  NT Loop Httpd.serve_forever () def html_listener_function (): Listen_on_port = 9000 #Set up to run on the local machine server_address = (' 127.0.0.1 ', Listen_on_port) htmlhandler.init () httpd = Basehttpserver.httpserver (server_address, Ht
  Mlhandler) print "Listening for Get on port" and Listen_on_port #Go into a The main event loop Httpd.serve_forever () Return import time fromThreading Import Thread Soap_thread = Thread (None, soap_listener_function) Html_thread = Thread (None, Html_listener_

 function) Soap_thread.start () #Pause before spawning the next thread time.sleep (1) html_thread.start ()

By defining Do_get and Do_post on the server, you can handle get and POST requests on a single server instance, but because of the nature of the simple event loops that you use, you can use threading technology to listen on different ports. This lets you run two server instances at the same time. Threading Technology is one of the methods, and using asynchronous event handlers is another method. Python 2.2 introduced the Asyncore module to support the latter technology more easily, as we described in the previous article in this column (see Resources). This time we will give an example of the use of the open-wire process technique. The Python 2.2 documentation gives good advice on using threading technology or using asynchronous technology.

[asynchronous methods are] really useful only if your program is largely subject to I/O restrictions. If your program is limited by the processor, then preemptive scheduling of threads may be what you really need. However, network servers are rarely subject to processor restrictions.

Figure 1 shows a browser view of a Web service description that is easy to understand.

Conclusion

Consider all this as an experimental material. Kafka has been quite outdated-it seems to have not been maintained since 2001, and it uses a rather poor XSLT style (the author frankly admits to being an XSLT rookie). But its ideas are very useful and valuable. It only takes a little effort to update it to SOAP 1.2 and expand its capabilities. The WSDL representation we provide is also just a starting point. You can also update it to WSDL 1.2 and expand it to show more information about the WEB service. It should also be updated to take advantage of the namespace axis and other XSLT features for more accurate processing.

XSLT is a sandbox, and developers who use a variety of languages and environments can do it. Kafka is developed by a determined. NET developer, but we can also learn it quickly and take advantage of it. This is the power of a common language (lingua franca) that can handle both XML and WEB services. We expect that the realm of XSLT modules that can be used for WEB services will continue to expand. If so, the basic techniques provided in this article may prompt Python programmers to use these useful techniques at once.

Related Article

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.