منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : Linq To XML
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
كاتب الموضوع : Islam Ibrahim
مقدمة

تم تدعيم Visual Basic 9 بمجموعة من المزايا الجديدة والجيدة والتي تتيح العمل بشكل أكثر فائدة عند التعامل مع XML باستخدام الواجهة الجديدة للبرمجة باستخدام LINQ والمسماة Linq To XML API , تعني Linq لغة الاستعلامات المضمنة Language Integrated Query والتي تتيح كتابة استعلامات للعديد من الأشياء مثل الكائنات Objects وقواعد البيانات Databases, و كذا XML بطريقة قياسية. ويقدم Visual Basic 2008 دعم عميق لـ Linq To XML عبر ما يسمى بـ XML Literals و XML axis properties , هذه الميزات تسمح بالتعامل مع XML بشكل سلس يمكن الاعتياد عليه بسهولة. Linq To XML هي واجهة جديدة مبنية في الذاكرة لمعالجة XML صممت لتزيد من قيمة وفائدة استعلامات Linq , بحيث يمكنك استخدام استعلامات Linq وتضمينها داخل XML Literals و XML axis properties بشكل مباشر مما يعني القدرة على إنشاء ومعالجة مستندات معقدة بمنتهى السهولة وبكم قليل من الكود, ستكتشف كيفية ذلك خلال بقية هذا المقال.

محارف XML والتعبيرات المضمنة XML Literals & Embedded Expressions

سابقاً عند التعامل مع XML من خلال الكود فإنك مضطر لاستخدام XML DOM (XML Document Object Model) واستخدام الفئات الخاصة بواجهة XML أي - XML API - مثل XMLReader, XMLSerializer, وغيرها, هذه الواجهة لن تساعد بالشكل المطلوب عندما نريد إنشاء XML واستخدام Linq, بالإضافة إلى أنها تستخدم لغة XPath الغير ضرورية عند استخدام Linq . كان هناك أسلوب آخر أيضًا للتعامل مع XML وهو فصل XML عن الشفرة البرمجية والتعامل معه باستخدام XSLT, XQuery, وXPath مباشرةً.

مع إصدار .NET 3.5 أصبح بوسعنا استخدام Linq To XML بسلاسة, بحيث يمكن استخدام XML Literals من أجل تضمين XML مباشرةً داخل الكود على سبيل المثال يمكن بناء مستند XML داخل الكود بالشكل التالي دون أي اعتراض من محرر الكود:


كود :
[color=#000000]Dim myXml = [COLOR=#0000bb]<?xml version[/color][color=#007700]=[/color][color=#dd0000]"1.0"[/color][COLOR=#0000bb]?>
[/COLOR]            <root>
                <node>This is XML</node>
            </root>[/COLOR]

المتغير myXml تم التعرف عليه من قبل محرر الكود على أنه كائن من النوع XDocument بفضل ميزة أخرى جديدة في Visual Basic 2008 تدعى استنتاج النوع محلياً Local Type Inference والتي تم استحداثها من أجل دعم Linq , بحيث يمكن التعرف على نوع المتغير دون تحديد نوعه عند تعريفه من خلال المترجم عن طريق اختبار الجزء الأيمن من تعريف المتغير. المثال السابق في الإصدارات السابقة لـ Visual Basic سيكون المتغير myXml من النوع Object, وبفضل استخدام الخيار الجديد Option Infer On في VB9 أصبح فيجوال بيسك قادراً على تحديد نوع المتغير كما لو تم تعريفه على أنه من النوع XDocument بشكل صريح, ولهذا يمكن الاستفادة من تعقب المترجم للأخطاء في الكود أثناء عملية Compiling وتداركها وتصحيحها. النوع XDocument واحد من الأنواع الجديدة المضمنة مع واجهة Linq To XML وهو يعمل بكفاءة في العديد من الحالات أكثر من XML DOM.

وكما هو ملاحظ فلا يوجد هناك تعارض عند استخدام محارف XML والكود الذي تكتبه , وكما يلاحظ أيضًا تلون عناصر XML في محرّر الكود والذي يدل على أن فيجوال بيسك قادر على استيعاب محارف XML على أنها نوع من أنواع البيانات, ومن الميزات المثيرة أيضًا أنه عندما تقوم بكتابة بداية وسم XML فإن فيجوال بيسك يقوم بتكملة end tag وتنسيقه بشكل تلقائي, وإذا قمت بتغيير وسم البداية فإن فيجوال بيسك سيقوم بتعديل وسم النهاية المقابل له.

وما يجعل XML Literlas أكثر فائدة هو التعبيرات المضمنة Embedded Expressions والتي تسمح بكتابة أي كود داخل XML Literal ويمكن استخدام أي تعبير , هذه التعبيرات كأي كود ستخضع للترجمة Compiling لذلك يمكن الاستفادة من تعقب المترجم للأخطاء من أجل تجنب الأخطاء عند كتابة تلك التعبيرات . ومن أجل كتابة تعبير مضمن يجب استخدام التركيب التالي:

كود :
[color=#000000][COLOR=#007700]<% [/color][color=#0000bb]expression [/color][COLOR=#007700]%>  
[/COLOR][/COLOR]

لنأخذ المثال التالي على كيفية كتابة تعبير مضمن داخل محارف XML بحيث يقوم الكود التالي بإضافة التاريخ والوقت الحالي داخل العنصر <node> :


كود :
[color=#000000][COLOR=#0000bb]Dim myXml [/color][color=#007700]= <[/color][color=#0000bb]root[/color][COLOR=#007700]>
                <[/COLOR][color=#0000bb]node[/color][color=#007700]><%= [/color][color=#0000bb]Now[/color][color=#007700]() %></[/color][color=#0000bb]node[/color][COLOR=#007700]>
            </[/COLOR][color=#0000bb]root[/color][COLOR=#007700]>  
[/COLOR][/COLOR]

لاحظ أن هذه المرة لم نقم بكتابة التعريف XML <?xml version="1.0"?> لهذا السبب سيستدل المترجم على المتغير myXml على أنه من النوع XElement بدلاً من XDocument, يعتبر XElement النوع الأساسي في Linq To XML API, فمستندات XML مبنية على كائنات XElement تلك. المثال السابق مثال بسيط فقط, ليس هناك أي قيود لاستخدام عدد محدّد من التعبيرات المضمنة, فيمكن كتابة تعابير متداخلة ضمن عدد غير محدود من التداخلات.

لنأخذ الآن مثالاً على استخدام Linq To XML لكتابة مستند XML يحتوي على الملفات الموجودة ضمن المجلد الحالي, وذلك باستخدام محارف XML والتعبيرات المضمنة:


كود :
[color=#000000][COLOR=#0000bb]    Sub Main[/color][COLOR=#007700]()
        [/COLOR][color=#0000bb]Dim files [/color][color=#007700]= [/color][color=#0000bb]From file In My[/color][color=#007700].[/color][color=#0000bb]Computer[/color][color=#007700].[/color][color=#0000bb]FileSystem[/color][color=#007700].[/color][color=#0000bb]GetFiles[/color][color=#007700]([/color][color=#0000bb]Environment[/color][color=#007700].[/color][color=#0000bb]CurrentDirectory[/color][color=#007700]) [/color][COLOR=#0000bb]_
                     Select My[/COLOR][color=#007700].[/color][color=#0000bb]Computer[/color][color=#007700].[/color][color=#0000bb]FileSystem[/color][color=#007700].[/color][color=#0000bb]GetFileInfo[/color][color=#007700]([/color][color=#0000bb]file[/color][COLOR=#007700])
        [/COLOR][color=#0000bb]Dim myXml [/color][color=#007700]= [/color][COLOR=#0000bb]_
  [/COLOR][color=#007700]<[/color][color=#0000bb]files[/color][COLOR=#007700]>
      <%= [/COLOR][COLOR=#0000bb]From file In files Select _
          [/COLOR][color=#007700]<[/color][color=#0000bb]file isReadonly[/color][COLOR=#007700]=
              <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]IsReadOnly [/color][COLOR=#007700]%>>
              <[/COLOR][color=#0000bb]name[/color][COLOR=#007700]>
                  <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]Name [/color][COLOR=#007700]%>
              </[/COLOR][color=#0000bb]name[/color][COLOR=#007700]>
              <[/COLOR][color=#0000bb]created[/color][COLOR=#007700]>
                  <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]CreationTime [/color][COLOR=#007700]%>
              </[/COLOR][color=#0000bb]created[/color][COLOR=#007700]>
              <[/COLOR][color=#0000bb]updated[/color][COLOR=#007700]>
                  <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]LastWriteTime [/color][COLOR=#007700]%>
              </[/COLOR][color=#0000bb]updated[/color][COLOR=#007700]>
              <[/COLOR][color=#0000bb]lenght[/color][COLOR=#007700]>
                  <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]Length [/color][COLOR=#007700]%>
              </[/COLOR][color=#0000bb]lenght[/color][COLOR=#007700]>
          </[/COLOR][color=#0000bb]file[/color][COLOR=#007700]> %>
  </[/COLOR][color=#0000bb]files[/color][COLOR=#007700]>

        [/COLOR][color=#0000bb]myXml[/color][color=#007700].[/color][color=#0000bb]Save[/color][color=#007700]([/color][color=#dd0000]"c:\MyFiles.xml"[/color][COLOR=#007700])

    [/COLOR][COLOR=#0000bb]End Sub  
[/COLOR][/COLOR]

الكود السابق سيقوم بتوليد مستند XML شبيه بالتالي:


كود :
[color=#000000][COLOR=#0000bb]<?xml version[/color][color=#007700]=[/color][color=#dd0000]"1.0" [/color][color=#0000bb]encoding[/color][color=#007700]=[/color][color=#dd0000]"utf-8"[/color][COLOR=#0000bb]?>
[/COLOR]<files>
  <file isReadonly="false">
    <name>ConsoleApplication1.exe</name>
    <created>2009-12-12T23:53:26.359375-08:00</created>
    <updated>2009-12-12T23:52:26.390625-08:00</updated>
    <lenght>18944</lenght>
  </file>
  <file isReadonly="false">
    <name>ConsoleApplication1.pdb</name>
    <created>2009-12-12T23:53:26.4375-08:00</created>
    <updated>2009-12-12T23:52:26.46875-08:00</updated>
    <lenght>42496</lenght>
  </file>
  <file isReadonly="false">
    <name>ConsoleApplication1.vshost.exe</name>
    <created>2009-12-12T23:53:26.4375-08:00</created>
    <updated>2009-12-12T22:14:11.28125-08:00</updated>
    <lenght>14328</lenght>
  </file>
</files>[/COLOR]

لاحظ في المثال السابق أننا قمنا أولاً بكتابة XML Literal ومن ثم قمنا بتضمين استعلام لينك بداخله والذي يقوم باختيار مجموعة من العناصر <file> والتي تمثل XElement , وذلك من أجل إنشاء المستند, وبهذه الطريقة يمكن أيضًا كتابة تعبيرات مضمنة متداخلة لغرض إنشاء مستندات أكثر تعقيداَ بعيداً عن الصعوبة, ويمكن قراءتها وفهمها بسهولة كل هذا دون الحاجة للاستعانة بـ XML DOM.

XML Axis Properties

تستخدم axis properties من أجل التنقل داخل مستند XML , وتوجد منها ثلاثة أنواع: descendant axis, child axis, attribute axis, تستخدم descendant axis للوصول إلى جميع عناصر XML التي لها اسم محدد والموجودة ضمن عنصر XML معيّن بغض النظر عن مستوى العنصر الذي نريد الوصول إليه, بينما تستخدم child axis للوصول فقط إلى العناصر الأبناء في عنصر XML معيّن, وهي تعمل بكفاءة أكثر من descendant axis , ويستحسن دائمًا استخدام child axis إلا إذا رغبت في البحث عن اسم عنصر معيّن في جميع مستويات مستند XML , وأخيرًا تستخدم attribute axis للوصول إلى XML attributes في عنصر XML معيّن.

على سبيل المثال, لنأخذ مستند XML الناتج في المثال السابق, يمكن الوصول إلى جميع العناصر <name> باستخدام descendant axis والذي يستخدم 3 نقاط متتالية (...) وذلك بكتابة: myXml…<name>, فإذا أردنا إنشاء عنصر XElement جديد يحتوي فقط على العناصر <name> في المستند السابق سنقوم بما يلي:


كود :
[color=#000000][COLOR=#0000bb]        Dim newxml [/color][color=#007700]= <[/color][color=#0000bb]names[/color][COLOR=#007700]>
                         <%= [/COLOR][color=#0000bb]myXml[/color][color=#007700]...<[/color][color=#0000bb]name[/color][COLOR=#007700]> %>
                     </[/COLOR][color=#0000bb]names[/color][COLOR=#007700]>

        [/COLOR][color=#0000bb]newxml[/color][color=#007700].[/color][color=#0000bb]Save[/color][color=#007700]([/color][color=#dd0000]"c:\MyFiles.xml"[/color][COLOR=#007700])  
[/COLOR][/COLOR]

والناتج سيكون شبيه بالتالي:

كود :
[color=#000000]  [COLOR=#0000bb]<?xml version[/color][color=#007700]=[/color][color=#dd0000]"1.0" [/color][color=#0000bb]encoding[/color][color=#007700]=[/color][color=#dd0000]"utf-8" [/color][color=#0000bb]?>[/color]  
- <names>
  <name>ConsoleApplication1.exe</name>  
  <name>ConsoleApplication1.pdb</name>  
  <name>ConsoleApplication1.vshost.exe</name>  
  <name>ConsoleApplication1.vshost.exe.manifest</name>  
  <name>ConsoleApplication1.xml</name>  
  </names>[/COLOR]

يمكن الحصول على نفس النتيجة إذا استخدمنا child axis properties ولكن هذه المرة بالمرور على كافة المستويات:


كود :
[color=#000000][COLOR=#0000bb]Dim names [/color][color=#007700]= <[/color][color=#0000bb]names[/color][COLOR=#007700]>
                <%= [/COLOR][color=#0000bb]myXml[/color][color=#007700].<[/color][color=#0000bb]file[/color][color=#007700]>.<[/color][color=#0000bb]name[/color][COLOR=#007700]> %>
            </[/COLOR][color=#0000bb]names[/color][COLOR=#007700]>  
[/COLOR][/COLOR]

وإذا كنا نرغب في استعادة محتوى عنصر XML بدلاً من العنصر نفسه يمكن استخدام الخاصية Value مثلاً:


كود :
[color=#000000][COLOR=#0000bb]        Dim names [/color][color=#007700]= <[/color][color=#0000bb]names[/color][COLOR=#007700]>
                        <%= [/COLOR][color=#0000bb]From file In myXml[/color][color=#007700]...<[/color][color=#0000bb]name[/color][color=#007700]> [/color][COLOR=#0000bb]Select _
                            [/COLOR][color=#007700]<[/color][color=#0000bb]filenames[/color][COLOR=#007700]>
                                <%= [/COLOR][color=#0000bb]file[/color][color=#007700].[/color][color=#0000bb]Value [/color][COLOR=#007700]%>
                            </[/COLOR][color=#0000bb]filenames[/color][COLOR=#007700]> %>
                    </[/COLOR][color=#0000bb]names[/color][COLOR=#007700]>  
[/COLOR][/COLOR]

وللوصول إلى IsReadOnly Attributes نحتاج لاستخدام attribute axis property والذي يستخدم العلامة @ , لنفترض أننا نريد إنشاء مستند جديد من المستند السابق يحتوي فقط على الملفات ذات الخاصية IsReadOnly = False سنكتب XML Literal جديد ونضع بداخله تعبير مضمن (الاستعلام التالي):

كود :
[color=#000000][COLOR=#0000bb]Dim files [/color][color=#007700]= <[/color][color=#0000bb]files[/color][COLOR=#007700]>
                        <%= [/COLOR][color=#0000bb]From File In myXml[/color][color=#007700]...<[/color][color=#0000bb]file[/color][color=#007700]> [/color][COLOR=#0000bb]_
                            Where File[/COLOR][color=#007700].@[/color][color=#0000bb]isReadonly [/color][color=#007700]= [/color][color=#dd0000]"false" [/color][COLOR=#0000bb]_
                            Select File [/COLOR][COLOR=#007700]%>
                    </[/COLOR][color=#0000bb]files[/color][COLOR=#007700]>
        [/COLOR][color=#0000bb]files[/color][color=#007700].[/color][color=#0000bb]Save[/color][color=#007700]([/color][color=#dd0000]"c:\names.xml"[/color][COLOR=#007700])  
[/COLOR][/COLOR]

باستخدام XML axis properties يمكننا التعامل مع XML بشكل سهل وقابل للقراءة , ولكن هناك أمر يجب أخذه في الحسبان هو أن XML بعكس فيجوال بيسك حساسة لحالة الأحرف Case-Sensitive فإذا قمت مثلاً بكتابة myXml…<Name> فلن تحصل على شيء لأنه لا يوجد عنصر اسمه Name داخل مستند XML الذي تم إنشاؤه أصلاُ, يوجد فقط <name> , وعلى كل حال هناك ميزة متاحة تمكننا من تجنب مثل هذه الأخطاء وهي تمكين IntelliSence ليدعم XML .