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

Source: Internet
Author: User
Tags ranges xsl xslt wsdl
Kafka-style soap endpoints

The Kafka-xsl SOAP Toolbox developed by Christopher Dix (see Resources) 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 based on SOAP 1.2. Listing 1 shows a sample Kafka endpoint: A SOAP server with a sum of two numbers (a typical and simple soap sample).

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

<?xml version= "1.0" encoding= "UTF-8"?>
   
    
    
  
   
    
  
   
    
    
  
   
    ADD
   
    
  
   
    http://www.topxml.com/
   
    
    
    
  
   
    
          
       
       
       
       
     
 
     
    
    
    
    
    
    
     
     
      
           
         
         
        
  
       
    
   

   
    
 

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 during the process of processing the entire XML document that makes up the SOAP message. The global variables Method and Methodns declare the XML element that makes up the message. After the SOAP envelope has been processed, the framework calls the Processpayload template, which passes in the payload of the XML principal. Xsl:for-each is the standard technique for switching contexts into desired nodes. Parameters A and B are read from this element using simple xpaths, and the framework is called again to help write out the response parameters. The Writeparameter template lets you specify the element name, data type, and value for 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 provides you with the mechanism you need to easily handle the HTTP portion of the protocol. See Listing 2.

Listing 2. Python HTTP Framework for Kafka SOAP endpoints implemented in Listing 1

#HTTP Listener code for SOAP Serverimport Basehttpserver#the processor class is the core of the XSLT Apifrom Ft.Xml.Xslt i Mport Processor#4xslt uses an inputsource system for reading Xmlfrom ft.xml import inputsourcesoap_impl_file = "Add.xsl" cl Kafkasoaphandler (Basehttpserver.basehttprequesthandler): Def init (CLS): From Ft.Lib import Uri #Set up a proces Sor instance to use Kafkasoaphandler.processor = Processor.processor () #Load it with add.xsl Add_uri = Uri.ospath Touri (Soap_impl_file, attemptabsolute=1) transform = InputSource.DefaultFactory.fromUri (Add_uri) KAFKASOAPHANDLER.P Rocessor.appendstylesheet (Transform) #Now The processor is prepped with a transform and can be used #over and over F    Or 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:missi Ng Content-length ' rEturn if Self.path! = '/add ': Self.send_error (404) Input_body = Self.rfile.read (Clen) #input_body is the Req Uest SOAP envelope and contents response_body = Self._run_through_kafka (input_body) #response_body is the response S    OAP Envelope and Contents self._send_response (+, ' OK ', response_body) return def _run_through_kafka (self, body):     #In 4Suite All inputsources has a base URIs in case they refer to #other URIs in some and resolution are required. #The SOAP messages is not having any such URI references, #So use a dummy base URI Source = INPUTSOURCE.DEFAULTF  Actory.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 self.se Nd_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 point Self.wfile.write (body) return listen_on_port = 8888#set up to run on local machineserver_address = (' 127.0.0.1 ', Lis Ten_on_port) kafkasoaphandler.init () httpd = Basehttpserver.httpserver (server_address, kafkasoaphandler) print " Listening on port, Listen_on_port#go into a The main event loophttpd.serve_forever ()

We commented on the list in detail, so it should be easy to understand. Note that this code is very simple, because it only needs to process the HTTP portion of the protocol, and the XML and SOAP parts are done by the KAFKA framework. The server is dedicated to an endpoint, so it only has 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, and the handler immediately calls the method as soon as it is registered with the server. The Classmethod built-in method is a new feature in Python 2.2, which is actually the version necessary for this 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 that data through a self instance reference on the normal method.

We tested the endpoint using the latest release of Soappy 0.10.1 (see Resources), which has a number of 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 Python listing2.py for the server. Then open another shell and run Python listing3.py, which will report the correct response, like Add result:7.0.

Listing 3: Soappy Client for the sum of two numbers

Import soappyendpoint = "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)

Usage description

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

Listing 4. WSDL for adding a service

<?xml version= "1.0" encoding= "UTF-8"?>
  
  
   
    
     
      
   
  

   
   
  
   
      
  

   
   
  
     
 
       
  
        
  
       
 
     

   
   
  
     
 
      
 
       
  
        
  
         
  
           
  
         
   
           
 
     

   
   
  
   
    
        
    
 
      
  

   
  
 

Listing 5 provides an XSLT script that renders useful information for end users. It is adapted from a transformation developed in 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 context of a WSDL), but it also licenses most of the WSDL 1.1 files currently in use.

Listing 5. XSLT Script

<?xml version= "1.0" encoding= "Utf-8"?>
  
  
   
   
   
  
   
   
  
   
   
  
   
   
  
   
   
  
          
 
    Service Summary: <xsl:value-of select= ' wsdl:definitions/@name '/>   
 
            
 
    

Service Summary:

Service " " hosted at

operation " " message details:

!--Yes, should Sue CSS, but keep this example simple-->

It is often convenient to provide a user-friendly 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 accomplishes this task. It actually offers three functions:

    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 unprocessed WSDL file
    3. For POST requests on port 8888: SOAP requests are executed.

Listing 6. Variant of Listing 2

#HTTP Listener code for SOAP Serverimport Basehttpserver#the processor class is the core of the XSLT Apifrom Ft.Xml.Xslt i Mport Processor#4xslt uses an inputsource system for reading Xmlfrom ft.xml import inputsourcesoap_impl_file = "Add.xsl" WS Dl_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 use Cls.processor = Processor.processor () #Load it with add.xsl Add_uri = Uri.ospathtouri (Soap_impl_file, AttemptAbsol  ute=1) Transform = InputSource.DefaultFactory.fromUri (Add_uri) cls.processor.appendStylesheet (transform) #Now the     Processor is prepped with a transform and can being used #over and over for the same transform #Prep for WSDL requests cls.wsdl = open (wsdl_file). Read () 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 for SOAP envelope an D contents response_body = Self._run_through_kafka (input_body) #response_body is the response SOAP envelope and cont    Ents _send_response (self, $, ' OK ', response_body) return def do_get (self): #response_body is the WSDL file  _send_response (self, $, ' OK ', self.wsdl) return def _run_through_kafka (self, body): #In 4Suite all Inputsources    The base URIs in case they refer to #other URIs in some and resolution are required. #The SOAP messages is not having any such URI references, #So use a dummy base URI Source = Inputsource.defaultfacto Ry.fromstring (Body, "urn:dummy") response = Self.processor.run (source) return Responseclass Htmlhandler (basehttpserv Er. 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 (transform) Wsdl_uri = Uri.ospathtouri (Wsdl_file, AttemptAbsolute =1) Source = InputSource.DefaultFactory.fromUri (Wsdl_uri) Cls.html_desc = Processor.run (source) return #Make INI T () a static class method init = Classmethod (init) def do_get (self): #response_body is the WSDL file _send_respons  E (self, $, ' OK ', Self.html_desc) Return#turn _send_response into a global function#for sharing between the Classesdef _send_response (handler, code, MSG, body): #Prepare A normal response Handler.send_response ($, ' OK ') #Send Stan Dard HTP Headers Handler.send_header (' Content-type ', ' text/html; Charset=utf-8 ') Handler.send_header ("Connection", " Close ") Handler.send_hEader ("accept-ranges", "bytes") handler.send_header (' Content-length ', Len (body)-1) handler.end_headers () #Send th E response prepared by the SOAP end point Handler.wfile.write (body) return def soap_listener_function (): Listen_on_ Port = 8888 #Set up-to-run on local Machine Server_address = (' 127.0.0.1 ', Listen_on_port) kafkasoaphandler.init () htt PD = Basehttpserver.httpserver (server_address, Kafkasoaphandler) print "Listening for GET and POST on port", Listen_on_po RT #Go into a The main event loop Httpd.serve_forever () def html_listener_function (): Listen_on_port = 9000 #Set up to Run on Local Machine Server_address = (' 127.0.0.1 ', Listen_on_port) htmlhandler.init () httpd = Basehttpserver.httpserve R (server_address, Htmlhandler) print "Listening for GET in Port", Listen_on_port #Go into a The main event loop Httpd.s Erve_forever () Returnimport timefrom threading Import threadsoap_thread = Thread (None, soap_listener_function) html_ Thread = Thread (None, Html_listener_function) Soap_thread.start () #Pause before spawning the next threadtime.sleep (1) html_thread.start () 

By defining Do_get and Do_post on the server, you can process GET and POST requests on a single server instance, but because of the nature of the simple event loop 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 an asynchronous event handler is another approach. Python 2.2 introduces the Asyncore module to make it easier to support the latter technology (see Resources) in the previous article in this column. This time we will give an example of the use of thread technology. The Python 2.2 documentation provides good advice on using threading technology or using asynchronous technology.

[Async methods are] really useful only if your program is heavily constrained by I/O. If your program is limited by the processor, the preemptive thread 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 of this as experimental material. Kafka has been quite outdated-it seems to have not been maintained since 2001, and it has used a rather poor XSLT style (its author frankly admits that he is an XSLT rookie). But the idea is very useful and valuable. It takes only a small effort to update it to SOAP 1.2 and extend its capabilities. The WSDL we provide indicates that the transformation is just a starting point. It can also be updated to WSDL 1.2 and extensible to display more information about WEB services. It should also be updated to take advantage of the namespace axes and other XSLT features for more correct processing.

XSLT is a sandbox in which developers of all languages and environments can work. Kafka was developed by a determined. NET developer, but we can also learn it quickly and take advantage of it. This is the power of having a common language (lingua franca) that can handle both XML and WEB services. We anticipate 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 immediately.

  • 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.