Meng Xianhui
เนื่องจากแพลตฟอร์มที่เป็นอิสระอย่างแท้จริงของ XML (Extensible Markup Language: eXtensible Markup Language) จึงค่อยๆ กลายเป็นสื่อหลักในการส่งข้อมูล XML เป็นภาษาที่อธิบายตัวเอง และข้อมูลเองก็มีข้อมูลเมตาอยู่แล้ว ซึ่งก็คือ ข้อมูลเกี่ยวกับข้อมูลนั้นเอง ตัวอย่างเช่น: "Mencius Chapter E 1757281793923net_lover1807581793923" ชุดข้อมูลนี้เป็นเรื่องยากที่จะดูว่ามันหมายถึงอะไร และไม่ชัดเจนว่าประกอบด้วยข้อมูลจำนวนเท่าใด อย่างไรก็ตาม หากเราใช้ XML เพื่ออธิบายดังนี้ สามารถมองเห็นความหมายของแต่ละส่วนข้อมูลได้อย่างชัดเจน:
<ข้อมูลส่วนบุคคล>
<บุคคล>
<ชื่อ>เม็นเซียส บทที่ E</ชื่อ>
<ความสูง>175</ความสูง>
<น้ำหนัก>72</น้ำหนัก>
<โทร>81793923</โทร>
</บุคคล>
<บุคคล>
<ชื่อ>net_lover</ชื่อ>
<ความสูง>180</ความสูง>
<น้ำหนัก>75</น้ำหนัก>
<โทร>81793923</โทร>
</บุคคล>
</ข้อมูลบุคคล>
จากส่วนด้านบนของ XML เราไม่เพียงแต่สามารถเห็นได้อย่างชัดเจนว่าแต่ละข้อมูลแสดงถึงอะไร แต่ยังรู้ด้วยว่าข้อมูลถูกแบ่งส่วนใด ในแอปพลิเคชันปกติของเรา ผลลัพธ์ที่เราได้รับอาจอยู่ในรูปแบบของอาร์เรย์ คอลเลกชัน หรือชุดระเบียน เราจะแปลงให้เป็นข้อมูลรูปแบบ XML ที่อธิบายตัวเองได้อย่างไร จากมุมมองของรูปแบบข้อมูล XML เป็นรูปแบบข้อความธรรมดาของสตริงล้วนๆ ง่าย รวดเร็ว และง่ายต่อการถ่ายโอน บางครั้งอาร์เรย์ก็โอนช้ามากโดยการอ้างอิง และยุ่งยากมากในการประมวลผล ชุดเป็นวัตถุทั้งสองซึ่งจะทำให้ประสิทธิภาพของคอมพิวเตอร์ลดลงในระหว่างการประมวลผล และวัตถุเหล่านี้เชื่อมโยงกับแพลตฟอร์มเฉพาะ ซึ่งต้องการให้แพลตฟอร์มมีกลไกการประมวลผลในตัวเพื่อจัดการการทำงานของวัตถุ XML เป็นมาตรฐาน W3C อยู่แล้วและไม่ขึ้นอยู่กับแพลตฟอร์ม ข้อกำหนดเดียวสำหรับคอมพิวเตอร์ของเราคือสามารถประมวลผลสตริง XML แบบง่ายได้ ซึ่งก็คือตัวแยกวิเคราะห์ XML และสามารถแยกวิเคราะห์สตริง XML และสามารถแยกส่วนข้อมูลได้อย่างง่ายดายผ่านอินเทอร์เฟซ ส่วนข้อมูลที่เป็นอิสระเพื่อให้เราสามารถเข้าถึงได้ ตัวแยกวิเคราะห์ XML มีขนาดเล็ก มีประสิทธิภาพ และสามารถพบได้ในทุกแพลตฟอร์ม เมื่อเราได้รับข้อมูล XML และแยกวิเคราะห์เป็นรูปแบบของตัวอย่างข้างต้นแล้ว เราก็สามารถแปลงข้อมูลเหล่านั้นเป็นรูปแบบต่างๆ ผ่านทาง XSLT (eXstensible Stylesheet Language Transformations) การใช้รูปแบบข้อมูล XML สำหรับการส่งข้อมูลจะทำให้งานเขียนโค้ดแอปพลิเคชันของเราง่ายขึ้นและสะดวกขึ้น และมีความสามารถในการปรับขนาดที่ดี
ต่อไป มาดูวิธีแปลงข้อมูลของเรากัน ตัวอย่างของเราเขียนภายใต้ Microsoft Windows 2000, IIS5, MSXML3 และ ADO2.6 ข้อมูลตัวอย่างใช้ฐานข้อมูลตัวอย่าง Northwind ที่มาพร้อมกับ Microsoft SQL Server7.0 เหตุผลที่เราใช้ SQL Server7 แทน SQL Server2000 ที่รองรับ XML คือการพิจารณาหลักการของความเป็นสากล จุดประสงค์ของเราคือการประมวลผลชุดระเบียนที่ได้รับจากแหล่งข้อมูลประเภทต่างๆ ไม่ใช่แค่เพื่อรองรับเอาต์พุต XML เช่นแหล่งข้อมูล SQL Server2000 . ใช้ ADO เนื่องจากมีรูปแบบที่หลากหลายและสามารถจัดการแหล่งข้อมูลประเภทต่างๆ ได้ ใช้ XML เนื่องจากสามารถส่งและแยกวิเคราะห์ได้อย่างรวดเร็ว แต่วิธีการประมวลผลในตัวอย่างนี้ยังเหมาะสำหรับสภาพแวดล้อมใด ๆ ที่มีตัวแยกวิเคราะห์ Microsoft XML, ADO2.5 หรือเวอร์ชันที่สูงกว่าของ Windows, IIS, SQL Server
เพื่อความง่าย เราเลือกเฉพาะผลิตภัณฑ์ที่ราคาต่อหน่วยน้อยกว่าหรือเท่ากับ 20 ดอลลาร์สหรัฐ ซึ่งมีสินค้าคงคลังมากกว่าหรือเท่ากับ 20 ดอลลาร์สหรัฐ และชื่อผลิตภัณฑ์น้อยกว่าหรือเท่ากับ 6 ตัวอักษร:
-
หรี่ objRecordset
ตั้ง objRecordset = Server.CreateObject("ADODB.Recordset")
objRecordset. เปิด _
"เลือกชื่อผลิตภัณฑ์, ราคาต่อหน่วย, UnitsInStock " _
& "จากผลิตภัณฑ์" _
& "โดยที่ราคาต่อหน่วย <= 20 " _
& "และ UnitsInStock >= 20 " _
& "และเลน(ชื่อผลิตภัณฑ์) <= 6 " _
& "เรียงตามชื่อผลิตภัณฑ์", _
"ผู้ให้บริการ=SQLOLEDB;" _
& "แหล่งข้อมูล=เซิร์ฟเวอร์ SQL บางตัว;" _
& "แคตตาล็อกเริ่มต้น=ลมเหนือ;" _
& "รหัสผู้ใช้=ชื่อผู้ใช้ของฉัน;" _
& "รหัสผ่าน=รหัสผ่านของฉัน;"
-
ตอนนี้เราใช้ 3 วิธีในการแปลงชุดบันทึกที่เราได้รับเป็นรูปแบบ XML
ขั้นแรก เราสามารถสำรวจชุดบันทึกทั้งหมด ใช้ XML DOM (Document Object Model) และสร้างแผนผังโหนด XML:
-
หรี่แสง objXMLDOM, objRootNode, objNode
ตั้งค่า objXMLDOM = Server.CreateObject("MSXML2.DOMDocument")
ตั้งค่า objRootNode = objXMLDOM.createElement("xml")
objXMLDOM.documentElement = objRootNode
ทำในขณะที่ไม่ objRecordset.EOF
ตั้งค่า objRowNode = objXMLDOM.createElement("แถว")
ตั้งค่า objNode = objXMLDOM.createElement("ProductName")
objNode.text = objRecordset.Fields.Item("ProductName").Value
objRowNode.appendChild (objNode)
ตั้งค่า objNode = objXMLDOM.createElement("ราคาต่อหน่วย")
objNode.text = objRecordset.Fields.Item("ราคาต่อหน่วย").มูลค่า
objRowNode.appendChild (objNode)
ตั้งค่า objNode = objXMLDOM.createElement("UnitsInStock")
objNode.text = objRecordset.Fields.Item("UnitsInStock").ค่า
objRowNode.appendChild (objNode)
objRootNode.appendChild (objRowNode)
objRecordset.MoveNext
วนซ้ำ
ตั้ง objNode = ไม่มีเลย
ตั้ง objRowNode = ไม่มีเลย
ตั้งค่า objRootNode = ไม่มีเลย
ตั้งค่า objRecordset = ไม่มีเลย
%>
ตอนนี้ เรามีวัตถุ XML DOM ประสิทธิภาพของวิธีนี้ไม่เหมาะเมื่อชุดระเบียนมีขนาดใหญ่ เนื่องจากวัตถุชุดระเบียน ADO และวัตถุ XML DOM ต้องถูกจัดเก็บไว้ในหน่วยความจำระบบในเวลาเดียวกัน
วิธีที่สองคือการสำรวจชุดระเบียนและสร้างสตริง XML โดยตรง:
-
หรี่ strXML
strXML = "<xml>"
objRecordset.MoveFirst
ทำในขณะที่ไม่ objRecordset.EOF
strXML = strXML & "<แถว>"
strXML = strXML & "<ชื่อผลิตภัณฑ์>" _
& objRecordset.Fields.Item("ชื่อผลิตภัณฑ์").ค่า _
& </ชื่อผลิตภัณฑ์>"
strXML = strXML & "<ราคาต่อหน่วย>" _
& objRecordset.Fields.Item("ราคาต่อหน่วย").ค่า _
& "</ราคาต่อหน่วย>"
strXML = strXML & "<UnitsInStock>" _
& objRecordset.Fields.Item("UnitsInStock").ค่า _
& "</UnitsInStock>"
strXML = strXML & "</แถว>"
objRecordset.MoveNext
วนซ้ำ
strXML = strXML & "</xml>"
ตั้งค่า objRecordset = ไม่มีเลย
-
อย่างไรก็ตาม ข้อบกพร่องที่ใหญ่ที่สุดของสองวิธีข้างต้นคือไม่สามารถใช้โค้ดซ้ำได้ เราได้เขียนชื่อของโหนดต่างๆ ไว้ หากเราค้นหาฟิลด์ที่แตกต่างกัน เราต้องเปลี่ยนโค้ดของเราด้วยตนเองเพื่อให้ตรงกับความต้องการของโหนดที่แตกต่างกัน แนวทางของเราด้านล่างจะเป็นเรื่องทั่วไปมากขึ้น
วิธีที่สาม: วิธีที่ใช้ซ้ำได้
-
หรี่ strXML
strXML = "<xml>"
objRecordset.MoveFirst
ทำในขณะที่ไม่ objRecordset.EOF
strXML = strXML & "<แถว>"
สำหรับแต่ละ varItem ใน objRecordset.Fields
strXML = strXML _
& "<" & varItem.name & ">" _
&varItem.value_
& "</" & varItem.name & ">"
ต่อไป
strXML = strXML & "</แถว>"
objRecordset.MoveNext
วนซ้ำ
strXML = strXML & "</xml>"
ตั้งค่า objRecordset = ไม่มีเลย
-
วิธีที่มีประสิทธิภาพมากกว่าคือการใช้วิธีการบันทึกในตัวของชุดระเบียนโดยตรง ซึ่งสามารถแปลงเนื้อหาของชุดระเบียนเป็นรูปแบบ XML ได้โดยอัตโนมัติ หลังจากที่เราเรียกวิธีการบันทึกแล้ว เราก็จะสามารถปล่อยอินสแตนซ์ของวัตถุชุดระเบียนในหน่วยความจำได้ทันที . วิธีการบันทึกมีพารามิเตอร์สองตัว: ตัวแรกคือตำแหน่งที่จะบันทึก XML และอีกตัวคือตัวบ่งชี้ที่ระบุรูปแบบในการบันทึกข้อมูล เราสามารถบันทึกข้อมูลเป็นวัตถุ XML DOM (วัตถุ ADO STREAM) หรือบันทึกโดยตรงเป็นวัตถุ ASP RESPONSE เพื่อประโยชน์ทั่วไป เราจะบันทึกเป็น XML DOM และใช้ค่าคงที่ adPersistXML ADO สำหรับพารามิเตอร์ตัวที่สอง . มีวิธีดังนี้:
-
ค่าคงที่ adPersistXML = 1
หรี่แสง objXMLDOM
ตั้งค่า objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")
objRecordset.save objXMLDOM, adPersistXML
ตั้งค่า objRecordset = ไม่มีเลย
-
วิธีนี้สะดวก รวดเร็ว และปราศจากข้อผิดพลาด ไม่จำเป็นต้องเปลี่ยนชื่อโหนดด้วยตนเองสำหรับการสืบค้นที่แตกต่างกัน อย่างไรก็ตาม XML ที่สร้างโดยวิธีนี้ไม่กระชับเพียงพอ ลองดูผลลัพธ์ที่สร้าง:
<xml
xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="โกศ:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType
ชื่อ = "แถว"
เนื้อหา = "eltOnly"
rs:CommandTimeout="30">
<s:AttributeType
ชื่อ = "ชื่อผลิตภัณฑ์"
อาร์เอส:number="1"
rs:writeunknown="true">
<s:datatype
dt:type="สตริง"
dt:maxLength="40"
rs:maybenull="false"/>
</s:ชนิดแอตทริบิวต์>
<s:ชนิดแอตทริบิวต์
name="ราคาต่อหน่วย"
อาร์เอส:number="2"
อาร์เอส: nullable = "จริง"
rs:writeunknown="true">
<s:datatype
dt:type="หมายเลข"
฿:dbtype="สกุลเงิน"
dt:maxLength="8"
rs:precision="19"
rs:fixedlength="true"/>
</s:ชนิดแอตทริบิวต์>
<s:ชนิดแอตทริบิวต์
name="UnitsInStock"
฿:number="3"
อาร์เอส: nullable = "จริง"
rs:writeunknown="true">
<s:datatype
dt:type="i2"
dt:maxLength="2"
rs:precision="5"
rs:fixedlength="true"/>
</s:AttributeType>
<s:extends type="rs:rowbase"/>
</s:ElementType>
</s:Schema>
<rs:ข้อมูล>
<z:แถว
ProductName="ชัย"
ราคาต่อหน่วย="18"
UnitsInStock="39"/>
<z:row
ProductName="คอนบุ"
ราคาต่อหน่วย = "6"
UnitsInStock="24"/>
<z:row
ProductName="เต้าหู้"
ราคาต่อหน่วย="23.25"
UnitsInStock="35"/>
</rs:data>
</xml>
XML ที่สร้างขึ้นโดยอัตโนมัติโดย ADO มีข้อมูลสคีมา ซึ่งอธิบายว่าโหนดและแอตทริบิวต์ใดบ้างที่ได้รับอนุญาตใน XML นี้ และประเภทข้อมูลใดที่ใช้ และโหนดข้อมูล เพิ่มเนมสเปซด้วย ข้อมูลสคีมาอาจมีประโยชน์เมื่อจำเป็นต้องมีการตรวจสอบความถูกต้องของข้อมูลหรือสำหรับการประมวลผลที่ซับซ้อนมากขึ้น แต่ในกรณีส่วนใหญ่ เราใช้ไคลเอ็นต์แบบบางและเราไม่ต้องการข้อมูลสคีมา เราสามารถใช้ XSLT เพื่อแยกข้อมูลที่เราต้องการและลบข้อมูลที่ซ้ำซ้อนออก ดังนั้นเราจึงเขียน "DataCleaner.xsl" ต่อไปนี้:
<?xml เวอร์ชัน = "1.0"?>
<xsl:stylesheet เวอร์ชัน = "1.0"
xmlns:xsl=" http://www.w3.org/1999/XSL/Transform "
xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="โกศ:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<xsl:output ละเว้น-xml-declaration="yes"/>
<xsl:แม่แบบที่ตรงกัน="/">
<xsl:ชื่อองค์ประกอบ="xml">
<xsl:for-each select="/xml/rs:data/z:row">
<xsl:ชื่อองค์ประกอบ="แถว">
<xsl:for-each select="@*">
<xsl:ชื่อองค์ประกอบ="{ชื่อ()}">
<xsl:value-of select="."/>
</xsl:องค์ประกอบ>
</xsl:สำหรับแต่ละ>
</xsl:องค์ประกอบ>
</xsl:สำหรับแต่ละ>
</xsl:องค์ประกอบ>
</xsl:แม่แบบ>
</xsl:สไตล์ชีท>
XSLT นี้มีคุณสมบัติที่นำมาใช้ซ้ำได้และใช้ได้กับผลลัพธ์การสืบค้นที่แตกต่างกัน ต่อไปนี้คือตัวอย่างวิธีใช้ XSLT นี้:
-
หรี่ strCleanXML, objXMLDOM_XSLT
ตั้งค่า objXMLDOM_XSLT = CreateObject("MSXML2.DOMDocument")
objXMLDOM_XSLT.load (Server.MapPath ("DataCleaner.xsl"))
strCleanXML = objXMLDOM.transformNode (objXMLDOM_XSLT)
ตั้ง objXMLDOM = ไม่มีเลย
ตั้ง objXMLDOM_XSLT = ไม่มีเลย
-
หลังจากการประมวลผลข้างต้น strClaenXML จะเป็นสตริง XML ที่เราต้องการ
<xml>
<แถว>
<ProductName>ชัย</ProductName>
<ราคาต่อหน่วย>18</ราคาต่อหน่วย>
<UnitsInStock>39</UnitsInStock>
</แถว>
<แถว>
<ProductName>คอนบุ</ProductName>
<ราคาต่อหน่วย>6</ราคาต่อหน่วย>
<UnitsInStock>24</UnitsInStock>
</แถว>
</xml>
สตริง XML ในรูปแบบด้านบนคือสไตล์ของชุดโหนดที่เรามักพบเห็น หากคุณไม่ต้องการประมวลผลฟิลด์เป็นโหนด แต่ประมวลผลเป็นโหนดแอตทริบิวต์ เราก็ต้องทำการเปลี่ยนแปลง DataCleaber เพียงเล็กน้อยเท่านั้น xsl:
<?xml เวอร์ชัน = "1.0"?>
<xsl:stylesheet เวอร์ชัน = "1.0"
xmlns:xsl=" http://www.w3.org/1999/XSL/Transform "
xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="โกศ:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<xsl:output ละเว้น-xml-declaration="yes"/>
<xsl:แม่แบบที่ตรงกัน="/">
<xsl:ชื่อองค์ประกอบ="xml">
<xsl:for-each select="/xml/rs:data/z:row">
<xsl:ชื่อองค์ประกอบ="แถว">
<xsl:for-each select="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:แอตทริบิวต์>
</xsl:สำหรับแต่ละ>
</xsl:องค์ประกอบ>
</xsl:สำหรับแต่ละ>
</xsl:องค์ประกอบ>
</xsl:แม่แบบ>
</xsl:สไตล์ชีท>
ต่อไปนี้คือผลลัพธ์ของการใช้สไตล์ใหม่ซึ่งสั้นกว่าการใช้โหนดเพื่อแสดงความยาวของฟิลด์มาก ความเร็วในการถ่ายโอนจะเร็วขึ้น:
<xml>
<row ProductName="ชัย" UnitPrice="18" UnitsInStock="39"/>
<row ProductName="Konbu" UnitPrice="6" UnitsInStock="24"/>
</xml>
จนถึงตอนนี้ เราได้แนะนำหลายวิธีในการรับข้อมูลรูปแบบ XML จากชุดระเบียน ADO และเรายังได้รับสตริงที่ง่ายที่สุดอีกด้วย แต่ยังมีหลายประเด็นที่คุณยังต้องใส่ใจ ค่าของฟิลด์บางค่ามีอักขระที่ไม่รองรับใน XML เช่น "'< >& เช่นชื่อของ P&G Procter & Gamble ชื่อของ ผลิตภัณฑ์ Gumbo Mix ของ Chef Anton ฯลฯ คุณต้องดำเนินการนี้เมื่อทำการแปลง ดำเนินการประมวลผลการเข้ารหัส มีปัญหาที่ควรทราบเมื่อใช้วิธีการบันทึกใน Microsoft ADO 2.6 SDK: 1. วิธีการบันทึกใช้งานได้กับชุดระเบียนแบบเปิดเท่านั้น 2. ชุดระเบียน ไม่รองรับฟิลด์ประเภท adVariant, adIDispatch และ adIUnknown
เพื่อปรับปรุงประสิทธิภาพให้ดียิ่งขึ้น คุณสามารถใส่งานการแปลงลงในส่วนประกอบ COM/COM+ และโค้ด ASP จะดำเนินการเฉพาะการนำเสนอข้อมูลขั้นสุดท้ายเท่านั้น แยกชั้นธุรกิจ ชั้นข้อมูล และชั้นการนำเสนอ ASP จำเป็นต้องเรียกส่วนประกอบข้อมูลเท่านั้น ส่วนประกอบข้อมูลจะเรียกขั้นตอนการจัดเก็บของฐานข้อมูล แปลงผลลัพธ์เป็น XML และสุดท้ายจะสตริงเฉพาะสตริง XML แบบธรรมดากลับไปยังโปรแกรม ASP และ ASP สามารถใช้ XSLT เพื่อแปลง XML และส่งผลลัพธ์ไปยังเบราว์เซอร์