Meng Xianhui
نظرًا لاستقلال النظام الأساسي الحقيقي لـ XML (لغة التوصيف القابلة للامتداد: لغة التوصيف القابلة للامتداد)، فقد أصبحت تدريجيًا الوسيلة الرئيسية لنقل البيانات. 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 (تحويلات لغة ورقة الأنماط القابلة للتوسيع). إن استخدام تنسيق بيانات 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.open _
"اختر اسم المنتج، سعر الوحدة، الوحدات في المخزون" _
& "من المنتجات" _
& "أين سعر الوحدة <= 20" _
& "وUnitsInStock >= 20" _
& "و LEN (اسم المنتج) <= 6 " _
& "الطلب حسب اسم المنتج"، _
"الموفر=SQLOLEDB;"
& "مصدر البيانات=SomeSQLServer؛ _"
& "الكتالوج الأولي = الرياح الشمالية؛ _"
& "معرف المستخدم=MyUserName;"
& "كلمة المرور = كلمة المرور الخاصة بي؛"
%>
الآن، نستخدم ثلاث طرق لتحويل مجموعة السجلات التي حصلنا عليها إلى تنسيق XML.
أولاً، يمكننا اجتياز مجموعة السجلات بأكملها، واستخدام XML DOM (نموذج كائن المستند)، وإنشاء شجرة عقدة XML:
<%
خافت objXMLDOM، objRootNode، objNode
تعيين objXMLDOM = Server.CreateObject("MSXML2.DOMDocument")
تعيين objRootNode = objXMLDOM.createElement("xml")
objXMLDOM.documentElement = objRootNode
افعل ذلك أثناء عدم استخدام objRecordset.EOF
تعيين objRowNode = objXMLDOM.createElement("row")
تعيين objNode = objXMLDOM.createElement("ProductName")
objNode.text = objRecordset.Fields.Item("ProductName").Value
objRowNode.appendChild(objNode)
تعيين objNode = objXMLDOM.createElement("UnitPrice")
objNode.text = objRecordset.Fields.Item("UnitPrice").Value
objRowNode.appendChild(objNode)
تعيين objNode = objXMLDOM.createElement("UnitsInStock")
objNode.text = objRecordset.Fields.Item("UnitsInStock").Value
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 & "<UnitPrice>" _
& objRecordset.Fields.Item("UnitPrice").Value _
& "</UnitPrice>"
strXML = strXML & "<UnitsInStock>" _
& objRecordset.Fields.Item("UnitsInStock").Value _
& "</UnitsInStock>"
strXML = strXML & "</row>"
objRecordset.MoveNext
حلقة
strXML = strXML & "</xml>"
تعيين objRecordset = لا شيء
%>
ومع ذلك، فإن العيب الأكبر في الطريقتين المذكورتين أعلاه هو أنه لا يمكن إعادة استخدام الكود. لقد قمنا بكتابة أسماء العقد إذا قمنا بالاستعلام عن حقول مختلفة، فيجب علينا أيضًا تغيير الكود الخاص بنا يدويًا لتلبية احتياجات العقد المختلفة. سوف يصبح نهجنا أدناه أكثر عمومية.
الطريقة الثالثة: الطريقة القابلة لإعادة الاستخدام.
<%
خافت strXML
strXML = "<xml>"
objRecordset.MoveFirst
افعل ذلك أثناء عدم استخدام objRecordset.EOF
strXML = strXML & "<صف>"
لكل varItem في objRecordset.Fields
ستركسمل = ستركسمل _
& "<" & varItem.name & ">" _
&varItem.value_
& "</" & varItem.name & ">"
التالي
strXML = strXML & "</row>"
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="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType
الاسم = "صف"
المحتوى = "eltOnly"
rs:CommandTimeout="30">
<s:AttributeType
الاسم = "اسم المنتج"
آر إس:رقم = "1"
rs:writeunknown="true">
<s:datatype
دت:نوع = "سلسلة"
دت:ماكسلينغث = "40"
rs:maybenull="false"/>
</s:AttributeType>
<s:AttributeType
الاسم = "سعر الوحدة"
آر إس:رقم = "2"
آر إس: لاغية = "صحيح"
rs:writeunknown="true">
<s:datatype
دينارا: نوع = "رقم"
rs:dbtype = "العملة"
دت:ماكسلينغث = "8"
رس: الدقة = "19"
رس:الطول الثابت = "صحيح"/>
</s:AttributeType>
<s:AttributeType
الاسم = "الوحدات في المخزون"
رس:رقم = "3"
آر إس: لاغية = "صحيح"
rs:writeunknown="true">
<s:datatype
دت:نوع = "i2"
دت:ماكسلينغث = "2"
رس: الدقة = "5"
رس:الطول الثابت = "صحيح"/>
</s:AttributeType>
<s:extends type="rs:rowbase"/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row
اسم المنتج = "تشاي"
سعر الوحدة = "18"
UnitsInStock="39"/>
<z:row
اسم المنتج = "كونبو"
سعر الوحدة = "6"
UnitsInStock="24"/>
<z:row
اسم المنتج = "التوفو"
سعر الوحدة = "23.25"
UnitsInStock="35"/>
</rs:data>
</xml>
يحتوي XML الذي تم إنشاؤه تلقائيًا بواسطة ADO على معلومات المخطط، التي تصف العقد والسمات المسموح بها في XML هذا وأنواع البيانات المستخدمة، وعقد البيانات هي كما تم زيادة مساحة الاسم. قد تكون معلومات المخطط مفيدة عندما يكون التحقق من صحة البيانات مطلوبًا أو لمعالجة أكثر تعقيدًا، ولكن، في معظم الحالات، نستخدم عملاء رفيعين ولا نحتاج إلى معلومات المخطط. يمكننا استخدام XSLT لفصل المعلومات التي نريدها وإزالة المعلومات الزائدة عن الحاجة. ولذلك نكتب ما يلي "DataCleaner.xsl":
<?xml version="1.0"?>
<xsl:نسخة ورقة الأنماط = "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="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<xsl:output omit-xml-declaration="yes"/>
<xsl:تطابق القالب="/">
<xsl:اسم العنصر = "xml">
<xsl:for-each حدد = "/xml/rs:data/z:row">
<xsl:اسم العنصر = "صف">
<xsl:for-each حدد="@*">
<xsl:element name="{name()}">
<xsl:قيمة التحديد = "."/>
</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 التي نريدها.
<إكسمل>
<صف>
<ProductName>شاي</ProductName>
<UnitPrice>18</UnitPrice>
<UnitsInStock>39</UnitsInStock>
</صف>
<صف>
<ProductName>كونبو</ProductName>
<UnitPrice>6</UnitPrice>
<UnitsInStock>24</UnitsInStock>
</صف>
</xml>
سلسلة XML في التنسيق أعلاه هي نمط مجموعة العقد الذي نراه غالبًا. إذا كنت لا ترغب في معالجة الحقل في عقدة، ولكنك تريد معالجته في عقدة سمة، فإننا نحتاج فقط إلى إجراء تغييرات طفيفة على DataCleaber. xsl:
<?xml version="1.0"?>
<xsl:نسخة ورقة الأنماط = "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="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<xsl:output omit-xml-declaration="yes"/>
<xsl:تطابق القالب="/">
<xsl:اسم العنصر = "xml">
<xsl:for-each حدد = "/xml/rs:data/z:row">
<xsl:اسم العنصر = "صف">
<xsl:for-each حدد="@*">
<xsl:اسم السمة = "{name()}">
<xsl:قيمة التحديد = "."/>
</xsl:السمة>
</xsl:لكل>
</xsl:العنصر>
</xsl:لكل>
</xsl:العنصر>
</xsl:قالب>
</xsl:ورقة الأنماط>
ما يلي هو نتيجة استخدام النمط الجديد، وهو أقصر بكثير من استخدام العقد لتمثيل طول الحقل. ستكون سرعة النقل أسرع:
<إكسمل>
<صف اسم المنتج = "Chai" UnitPrice = "18" UnitsInStock = "39"/>
<row ProductName = "Konbu" UnitPrice = "6" UnitsInStock = "24"/>
</xml>
لقد قدمنا حتى الآن عدة طرق للحصول على بيانات تنسيق XML من مجموعات سجلات ADO، كما حصلنا على السلسلة الأكثر تبسيطًا. ولكن هناك العديد من المشكلات التي لا تزال بحاجة إلى الانتباه إليها. تحتوي بعض قيم الحقول على أحرف غير مدعومة في XML، مثل: "'< >&، مثل اسم P&G Procter & Gamble، واسم منتج Gumbo Mix الخاص بالشيف Anton، وما إلى ذلك. يجب عليك القيام بذلك عند التحويل. تنفيذ معالجة الترميز. توجد مشكلات يجب ملاحظتها عند استخدام أسلوب الحفظ في Microsoft ADO 2.6 SDK: 1. تعمل طريقة الحفظ فقط على مجموعة السجلات المفتوحة؛ مع حقول adVariant، وadIDispatch، وadIUnknown غير مدعومة savw؛ 3. هناك نوعان من القيود عند حفظ مجموعات السجلات الهرمية (أشكال البيانات): لا يمكن حفظ المعلمات ومجموعات السجلات التي تحتوي على تحديثات لم يتم حلها.
من أجل تحسين الأداء بشكل أكبر، يمكنك وضع عملية التحويل في مكونات COM/COM+، ويقوم رمز ASP فقط بتنفيذ العرض النهائي للبيانات. يحتاج ASP لفصل طبقة الأعمال وطبقة البيانات وطبقة العرض التقديمي فقط إلى استدعاء مكون البيانات، ويستدعي الإجراء المخزن لقاعدة البيانات، ويحول النتيجة إلى XML، وأخيرًا يعيد سلسلة XML البسيطة إلى برنامج ASP. ويمكن لـ ASP استخدام XSLT لتحويل XML وإرسال النتيجة إلى المتصفح.