激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 使用Python下的XSLT API進行web開發的簡單教程

使用Python下的XSLT API進行web開發的簡單教程

2020-06-07 10:25Python教程網 Python

這篇文章主要介紹了使用Python下的XSLT API進行web開發的簡單教程,本文來自于IBM官方網站技術文檔,需要的朋友可以參考下

Kafka 樣式的 soap 端點

Christopher Dix 所開發的“Kafka — XSL SOAP 工具箱”(請參閱 參考資料)是一種用于構造 SOAP 端點的 XSLT 框架。它只涵蓋了 SOAP 1.1,但 Kafka 端點演示了傳遞 UserLand SOAP 驗證器(UserLand SOAP Validator)的能力,并且根據 SOAP 1.2 對它進行更新似乎并不太困難。 清單 1展示了一個樣本 Kafka 端點:求兩數之和的 SOAP 服務器(一個典型而簡單的 SOAP 樣本)。

清單 1. 求兩數之和的 Kafka SOAP 端點

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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 -->
  <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 as Double, B as Double ) as Double -->
  <xsl:template name="ProcessPayload">
   <xsl:param name="Payload"/>
   <xsl:for-each select="$Payload">
     <!-- This is 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 takes the qualified name
       for a response parameter as well 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:double'"/>
     </xsl:call-template>
   </xsl:for-each>
  </xsl:template>
  
</xsl:stylesheet>

XSLT 端點導入 SOAP 框架(文件 kafka/soap.xsl),然后設置該框架將要使用的參數,并設置它在處理構成 SOAP 消息的整個 XML 文檔的過程中將要分派的模板。全局變量 Method 和 MethodNS 聲明了組成消息的 XML 元素。在處理完 SOAP 信封之后,該框架調用 ProcessPayload 模板,該模板傳入了 XML 主體的有效負載。 xsl:for-each 是將上下文切換成想要的節點的標準技巧。參數 A 和 B 是使用簡單 XPaths 從這個元素讀取的,而框架被再次調用以幫助寫出響應參數。 WriteParameter 模板讓您指定元素名稱、數據類型和每個輸出參數的值。本示例中的響應值是將兩個輸入參數相加所得的結果。

將這個端點部署為服務器相當于設置一個 HTTP 偵聽器。Python 的 BaseHTTPServer 模塊向您提供了所需的機制,能夠輕而易舉地處理該協議的 HTTP 部分。請參閱 清單 2。

清單 2. 用于清單 1 中所實現的 Kafka SOAP 端點的 Python HTTP 框架

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#HTTP Listener code for SOAP server
import BaseHTTPServer
#The processor class is the core of the XSLT API
from Ft.Xml.Xslt import Processor
#4XSLT uses an InputSource system for reading XML
from Ft.Xml import InputSource
SOAP_IMPL_FILE = "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_uri = Uri.OsPathToUri(SOAP_IMPL_FILE, attemptAbsolute=1)
    transform = InputSource.DefaultFactory.fromUri(add_uri)
    KafkaSoapHandler.processor.appendStylesheet(transform)
    #Now the processor is prepped with a transform and can be 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(200, 'OK', response_body)
    return
  def _run_through_kafka(self, body):
    #In 4Suite all InputSources have base URIs in case they refer to
    #other URIs in some way and resolution is required.
    #The SOAP messages will not have any such URI references,
    #So use a dummy base URI
    source = InputSource.DefaultFactory.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(200, 'OK')
    #Send standard HTP headers
    self.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 point
    self.wfile.write(body)
    return
 
listen_on_port = 8888
#Set up to run on local machine
server_address = ('127.0.0.1', listen_on_port)
KafkaSoapHandler.init()
httpd = BaseHTTPServer.HTTPServer(server_address, KafkaSoapHandler)
print "Listening on port", listen_on_port
#Go into a the main event loop
httpd.serve_forever()

我們詳細地注釋了該清單,因此它應該是易于理解的。請注意,這段代碼非常簡單,這是因為它僅需處理該協議的 HTTP 部分,而將 XML 和 SOAP 部分的工作交由 Kafka 框架完成。該服務器專用于一個端點,因此它只須對 XSLT 轉換進行一次解析和設置,然后它就可以簡單地反復為每次新的請求運行該轉換。這就是將處理器設置遷移到特殊的類方法中的原因,處理程序一注冊到服務器就立即調用該方法。 classmethod 內置方法是 Python 2.2 中的新功能,實際上該版本是本例和后面的示例所必需的版本。它提供了隱式類對象 (cls) ,您可以將靜態數據(如已準備好的處理器實例)附加到該對象上,然后通??梢酝ㄟ^普通方法上的 self 實例引用來使用該數據。

我們使用 SOAPpy 0.10.1 的最新發行版(請參閱 參考資料)測試了該端點,該發行版具有許多很棒的新功能,稍后我們將在本專欄中進行討論。 清單 3是使用該端點的 SOAPpy 客戶機。打開一個命令 shell 并為服務器運行 python listing2.py。然后打開另一個 shell 并運行 python listing3.py,該命令將報告正確的響應,形如 Add result: 7.0。

清單 3: 用于求兩數之和的 SOAPpy 客戶機

?
1
2
3
4
5
6
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)

使用描述

正如我們先前所說的,不僅 XML 中的有效負載是有用的 Web 服務特性,描述也是有用的特性。 清單 4是一個用于添加服務的 WSDL 文件,它是根據 Christopher Dix 的原始文件修改而得到的。它是 WSDL 1.1 版本的。

清單 4. 用于添加服務的 WSDL

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?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:Add" />
   <output message="tns:AddResponse" />
  </operation>
 </portType>
 <binding name="adder-soap-binding" type="tns:adder-port-type"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
         style="rpc"/>
  <operation name="Add">
   <soap:operation soapAction="http://tempuri.org/"/>
   <input>
    <soap:body use="encoded" namespace="http://www.topxml.com/"
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
   </input>
   <output>
    <soap:body use="encoded" namespace="http://www.topxml.com/"
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
   </output>
  </operation>
 </binding>
 <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>

清單 5提供了一個為端點用戶呈現有用信息的 XSLT 腳本。它是從先前的 developerWorks 文章“WSDL processing with XSLT”(請參閱 參考資料)中所開發的一個轉換改編而來的。它使用了許多自由方式(liberty)和快捷方式(尤其是在它處理 WSDL 上下文中的限定名時),但它也許可用于目前使用的大多數 WSDL 1.1 文件。

清單 5. XSLT 腳本

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?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:key name='message' match="wsdl:definitions/wsdl:message"
      use='@name'/>
 <xsl:key name='port-type' match="wsdl:definitions/wsdl:portType"
      use='@name'/>
 <xsl:key name='binding' match="wsdl:definitions/wsdl:binding"
      use='@name'/>
 <xsl:key name='service' match="wsdl:definitions/wsdl:service"
      use='@name'/>
 <xsl:template match='/'>
  <html>
  <head>
   <title>
Service summary: <xsl:value-of select='wsdl:definitions/@name'/>
   </title>
   <meta http-equiv="content-type" content="text/html"
      charset="UTF-8"/>
  </head>
  <body>
    <h1>
Service summary: <xsl:value-of select='wsdl:definitions/@name'/>
    </h1>
    <p><xsl:value-of select='wsdl:definitions/@documentation'/></p>
    <xsl:apply-templates select="wsdl:definitions/wsdl:service"/>
  </body>
   </html>
  </xsl:template>
  <xsl:template match='wsdl:service'>
   <div style="background: #ccffff">
    Service "<xsl:value-of select='@name'/>" hosted at
   <code>
    <xsl:value-of select='wsdl:port/soap:address/@location'/>
   </code>
    <xsl:variable name="binding"
     select="key('binding',
           substring-after(wsdl:port/@binding, ':'))"
    />
    <xsl:variable name="port-type"
     select="key('port-type',
           substring-after($binding/@type, ':'))"
    />
    <xsl:apply-templates select="$port-type/wsdl:operation"/>
   </div>
  </xsl:template>
 <xsl:template match='wsdl:operation'>
  <p>Operation "<b><xsl:value-of select='@name'/></b>" message details:</p>
  <!-- Yes, should sue CSS, but keep this example simple -->
  <table border="1" width="50%">
   <tbody>
    <xsl:if test="wsdl:input">
     <xsl:call-template name='message-role'>
      <xsl:with-param name="role-node" select="wsdl:input"/>
     </xsl:call-template>
    </xsl:if>
    <xsl:if test="wsdl:output">
     <xsl:call-template name='message-role'>
      <xsl:with-param name="role-node" select="wsdl:output"/>
     </xsl:call-template>
    </xsl:if>
    <xsl:if test="wsdl:fault">
     <xsl:call-template name='message-role'>
      <xsl:with-param name="role-node" select="wsdl:fault"/>
     </xsl:call-template>
    </xsl:if>
   </tbody>
  </table>
 </xsl:template>
 <xsl:template name='message-role'>
  <xsl:param name="role-node"/>
  <xsl:variable name="role-name"
         select="local-name($role-node)"/>
  <xsl:variable name="message"
   select="key('message',
       substring-after($role-node/@message, ':'))"
   />
  <tr>
   <td><xsl:value-of select='$role-name'/></td>
   <td>
    <table width="100%">
     <xsl:apply-templates select="$message/wsdl:part"/>
    </table>
   </td>
  </tr>
 </xsl:template>
 <xsl:template match='wsdl:part'>
  <tr>
   <td width="50%"><b><xsl:value-of select='@name'/></b></td>
   <td><xsl:value-of select='@type'/></td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

通常在 Web 服務本身所在的主機上提供該服務人性化的 WSDL 描述是很方便的。 清單 6是 清單 2的變體,它也完成這一任務。它實際上提供三種功能:

  1.     對于端口 9000 上的 GET 請求:提供該 Web 服務調用消息的易于理解的描述
  2.     對于端口 8888 上的 GET 請求:提供未經處理的 WSDL 文件
  3.     對于端口 8888 上的 POST 請求:執行 SOAP 請求。

清單 6. 清單 2 的變體

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#HTTP Listener code for SOAP server
import BaseHTTPServer
#The processor class is the core of the XSLT API
from Ft.Xml.Xslt import Processor
#4XSLT uses an InputSource system for reading XML
from Ft.Xml import InputSource
SOAP_IMPL_FILE = "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 use
    cls.processor = Processor.Processor()
    #Load it with add.xsl
    add_uri = Uri.OsPathToUri(SOAP_IMPL_FILE, attemptAbsolute=1)
    transform = InputSource.DefaultFactory.fromUri(add_uri)
    cls.processor.appendStylesheet(transform)
    #Now the processor is prepped with a transform and can be 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 SOAP envelope and contents
    response_body = self._run_through_kafka(input_body)
    #response_body is the response SOAP envelope and contents
    _send_response(self, 200, 'OK', response_body)
    return
  def do_GET(self):
    #response_body is the WSDL file
    _send_response(self, 200, 'OK', self.wsdl)
    return
  
  def _run_through_kafka(self, body):
    #In 4Suite all InputSources have base URIs in case they refer to
    #other URIs in some way and resolution is required.
    #The SOAP messages will not have any such URI references,
    #So use a dummy base URI
    source = InputSource.DefaultFactory.fromString(body, "urn:dummy")
    response = self.processor.run(source)
    return response
class HtmlHandler(BaseHTTPServer.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 init() a static class method
  init = classmethod(init)
  def do_GET(self):
    #response_body is the WSDL file
    _send_response(self, 200, '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(200, 'OK')
    #Send standard 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 the 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()
  httpd = BaseHTTPServer.HTTPServer(server_address, KafkaSoapHandler)
  print "Listening for GET and POST on port", listen_on_port
  #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.HTTPServer(server_address, HtmlHandler)
  print "Listening for GET on port", listen_on_port
  #Go into a the main event loop
  httpd.serve_forever()
  return
import time
from threading 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()

通過在服務器上定義 do_GET 和 do_POST ,您可以在單個服務器實例上處理 GET 和 POST 請求,但是因為所使用的簡單事件循環的性質,您可以使用線程技術在不同端口上進行偵聽。這讓您同時運行兩個服務器實例。線程技術是方法之一,而使用異步事件處理程序是另一種方法。Python 2.2 為更輕松地支持后一種技術而引入了 asyncore 模塊,我們在本專欄的上一篇文章中介紹了這種方法(請參閱 參考資料)。這一次我們將舉例說明線程技術的用法。關于使用線程技術還是使用異步技術的問題,Python 2.2 文檔提出了很好的建議。

僅當您的程序很大程度上受 I/O 限制時,[異步方法才是] 真正實用的。如果您的程序受處理器限制,那么搶先式調度的線程可能是您所真正需要的。但是,網絡服務器很少受處理器限制。

圖 1顯示了易于理解的 Web 服務描述的瀏覽器視圖。

使用Python下的XSLT API進行web開發的簡單教程

結束語

請將這一切都看作實驗素材。Kafka 已經相當落伍了 — 它似乎從 2001 年以來就沒有得到過維護,并且它使用了相當差勁的 XSLT 樣式(其作者坦率地承認自己是個 XSLT 菜鳥)。但其思想是非常有用的,并且很有價值。只需要作很小的努力就可以將它更新到 SOAP 1.2 并擴展其能力。我們所提供的 WSDL 表示轉換也只是一個起點。也可以將它更新到 WSDL 1.2 并可擴展它以顯示關于 Web 服務的更多信息。還應該更新它以利用名稱空間軸和其它 XSLT 功能以便進行更為正確的處理。

XSLT 是一個沙箱,使用各種語言和環境的開發人員都可以在其中施展身手。Kafka 是由一位堅定的 .NET 開發人員開發的,但我們也可以很快地學會它和利用它。這就是擁有一種既可以處理 XML 也可處理 Web 服務的通用語言(lingua franca)的威力。我們預計可以使用用于 Web 服務的 XSLT 模塊的領域將繼續擴展。如果是這樣,本文所提供的基本技術可能會促使 Python 程序員們馬上使用這些有用的技術。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产日韩一区二区三区在线观看 | 久久久久久久久成人 | 中国a毛片 | 91成人在线免费观看 | 国产一级免费在线视频 | 黄色特级片黄色特级片 | 久久草在线视频国产 | 中文字幕一二三区芒果 | 中文字幕亚洲一区二区三区 | 国产在线观看一区二区三区 | 久久成人免费网 | 欧美成人一级 | 中文字幕在线观看亚洲 | 2021年无线乱码播放高清完整 | 日本黄色免费播放 | 国产一级在线观看视频 | 久草在线资源福利站 | 精品久久久久久久久中文字幕 | 午夜a狂野欧美一区二区 | 91精品最新国内在线播放 | 欧美一级黄色影院 | 欧美极品欧美精品欧美视频 | 久久精品一级片 | 久久6国产 | 黄在线看 | 国产黄色一级大片 | 精品亚洲二区 | 91一区二区在线观看 | 毛片在线免费视频 | 日本羞羞的午夜电视剧 | 奇米影视亚洲精品一区 | 免费a级黄色片 | 亚洲国产精品99 | 亚洲精品成人18久久久久 | 蜜桃网站免费 | 成人区精品一区二区婷婷 | 国产午夜免费视频 | 国产精品久久久免费看 | 国产1区2| 久久久久久久久久91 | 姑娘第5集高清在线观看 |