نحوه انجام اعمال متداول روی اسناد XML توسط LINQ to XML - قسمت اول
  در این مقاله به معرفی نحوه ی انجام اعمال متداول جهت خواندن و اجرای کوئری های مختلف بر روی اسناد XML و با استفاده از دستورات LINQ to XML می پردازیم.
   LINQ
   ۱۱۴۴۵
   دانلود
   مرتضی صحراگرد
   ۱۳۸۹/۶/۱۲
ارسال لینک صفحه برای دوستان ارسال لینک صفحه برای دوستان  اضافه کردن به علاقه مندیها اضافه کردن به علاقه مندیها   نسخه قابل چاپ نسخه قابل چاپ

 

مقدمه:

شرکت مایکروسافت از زمان انتشار نسخه های اولیه برنامه ی ویژوال استودیو و پلتفرم DotNet همواره سعی نموده است که با ارائه ی API های مناسب و متعدد، انجام اعمال متداول بر روی اسناد XML را تسهیل نماید. اما با توجه به اینکه اغلب برنامه نویسان معمولا به طور حرفه ای و تمام وقت با اسناد XML سر و کار ندارند و یادگیری API های مربوطه نیز بسیار زمانبر و فرار می باشند، همواره درگیر بودن با زبان XML یکی از چالش های موجود، بوده است.

ضمنا این API ها اغلب به طور ذاتی دارای پیچیدگی هایی می باشند که یادگیری صحیح آن ها نیز نیاز به تلاش و صرف زمان قابل ملاحظه ای دارد.

با ظهور زبان LINQ to XML انقلابی در زمینه کار با اسناد XML به وجود آمد. با استفاده از این زبان به راحتی هر چه تمام تر می توان روی اسناد XML کوئری زد و اعمال متداول را انجام داد.

این مقاله به شکل طرح مشکل و ارائه ی راه حل نوشته شده است تا جوابگوی نیاز های خاص و متداول توسعه گران باشد.

آغاز:

در این مقاله برای انجام مثال ها از یک سند XML به نام Employees.xml استفاده می کنیم که حاوی مشخصات فرضی چهار کارمند می باشد. محتوای فایل مربوطه را در قسمت زیر ملاحظه می نمایید.

<?xml version="1.0" encoding="utf-8" ?>
<Employees>
    <Employee>
        <EmpId>1</EmpId>
        <Name>Sam</Name>
        <Sex>Male</Sex>
        <Phone Type="Home">423-555-0124</Phone>
        <Phone Type="Work">424-555-0545</Phone>
        <Address>
            <Street>7A Cox Street</Street>
            <City>Acampo</City>
            <State>CA</State>
            <Zip>95220</Zip>
            <Country>USA</Country>
        </Address>
    </Employee>
    <Employee>
        <EmpId>2</EmpId>
        <Name>Lucy</Name>
        <Sex>Female</Sex>
        <Phone Type="Home">143-555-0763</Phone>
        <Phone Type="Work">434-555-0567</Phone>
        <Address>
            <Street>Jess Bay</Street>
            <City>Alta</City>
            <State>CA</State>
            <Zip>95701</Zip>
            <Country>USA</Country>
        </Address>
    </Employee>
    <Employee>
        <EmpId>3</EmpId>
        <Name>Kate</Name>
        <Sex>Female</Sex>
        <Phone Type="Home">166-555-0231</Phone>
        <Phone Type="Work">233-555-0442</Phone>
        <Address>
            <Street>23 Boxen Street</Street>
            <City>Milford</City>
            <State>CA</State>
            <Zip>96121</Zip>
            <Country>USA</Country>
        </Address>
    </Employee>
    <Employee>
        <EmpId>4</EmpId>
        <Name>Chris</Name>
        <Sex>Male</Sex>
        <Phone Type="Home">564-555-0122</Phone>
        <Phone Type="Work">442-555-0154</Phone>
        <Address>
            <Street>124 Kutbay</Street>
            <City>Montara</City>
            <State>CA</State>
            <Zip>94037</Zip>
            <Country>USA</Country>
        </Address>
    </Employee>
</Employees>

تذکر:

قبل اینکه به تشریح سند XML بالا پرداخته شود، قرارداد می کنیم که:

  1. از واژه ی عنصر به جای المنت (Element) استفاده می کنیم. در زبان XML نامی که بلافاصله بعد از علامت کوچکتر یعنی ">" می آید، به عنوان المنت خطاب می شود. به طور مثال در کدهای XML بالا عناصر Employee، Employees، EmpId، Name، Phone و غیره وجود دارند.
     

  2. از واژه ی خصوصیت به جای واژه ی Attribute استفاده می کنیم. به طور مثال در کدهای XML بالا واژه ی Type در عنصر Phone را خصوصیت Type خطاب می کنیم.


فایل XML بالا مشخصات چهار کارمند را ارائه می کند که این مشخصات شامل موارد زیر می باشند:

  • شناسه کارمند (EmpId)

  • نام (Name)

  • جنسیت (Sex)

  • شماره تلفن(Phone) و نوع شماره تلفن (Type) که به صورت یک خصوصیت ایجاد شده است.

  • آدرس (Address) که در درون خود نیز شامل عناصری به نام های Street، City، State،Zip، Country می باشد.

برای مثال های انجام شده در این مقاله، وارد نمودن فضاهای نامی زیر الزامی می باشد.

using System.Linq;
using System.Xml.Linq;

اکنون به طرح مشکلات و ارائه ی راه حل های موجود می پردازیم.

1 . چگونه محتوای یک فایل XML را بخوانیم؟

در این مقاله از امکانات موجود در کلاس XElement استفاده می کنیم. کلاس XElement دارای متدی به نام Load می باشد. این متد آدرس فایل XML را گرفته و محتوای آن را لود می نماید. سپس با استفاده از متد Elements می توانیم به دنباله ای(Sequence) از عناصر Employee دسترسی داشته باشیم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
IEnumerable<XElement> employees = xelement.Elements();
 
// Read the entire XML
foreach (var employee in employees)
{
    Console.WriteLine(employee);
}

نتیجه:


 

2 . چگونه می توان به یک عنصر خاص از تمامی کارمندان دسترسی پیدا نمود؟

اکنون قصد داریم فقط نام تمامی کارمندان موجود در فایل XML را نمایش دهیم. برای انجام این کار باید توجه داشته باشید که کلاس XElement دارای صفتی به نام Value می باشد که محتوای آن عنصر را نگهداری می کند. ضمنا متد Element مشخصات یک عنصر خاص را برمی گرداند. به یاد داشته باشید که در صورتی که عنصر مربوطه وجود نداشته باشد، مقدار برگشتی این متد null می باشد.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
IEnumerable<XElement> employees = xelement.Elements();
 
Console.WriteLine("List of all Employee Names :");
foreach (var employee in employees)
{
    Console.WriteLine(employee.Element("Name").Value);
}

نتیجه:


 

3 . چگونه می توان به چندین عنصر از هر کارمند دسترسی پیدا نمود؟

اکنون قصد داریم که به عناصر نام و شناسه (EmpId) هر کارمند دسترسی داشته باشیم.

نحوه انجام کار مشابه مثال قبلی می باشد.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
IEnumerable<XElement> employees = xelement.Elements();
 
Console.WriteLine("List of all Employee Names along with their ID:");
foreach (var employee in employees)
{
    Console.WriteLine("{0} has Employee ID {1}",
        employee.Element("Name").Value,
        employee.Element("EmpId").Value);
}

نتیجه:


 

4 . چگونه می توان بر روی یک کوئری شرایطی را اعمال نماییم؟

اکنون قصد داریم به کارمندانی دسترسی داشته باشیم که جنسیت آن ها Female می باشد.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var name = from nm in xelement.Elements("Employee")
           where (string)nm.Element("Sex") == "Female"
           select nm;
 
Console.WriteLine("Details of Female Employees:");
foreach (XElement xEle in name)
    Console.WriteLine(xEle);

نتیجه:


 

5 . چگونه می توان به خصوصیات (Attributes) دسترسی پیدا نمود؟

اکنون قصد داریم که شماره تلفن خانه های کارمندان را چاپ کنیم. برای این منظور باید شماره هایی که خصوصییت Type آن ها برابر Home می باشد را بازیابی کنیم. این عمل را می توانیم توسط متد Attribute مربوط به کلاس XElement انجام دهیم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var homePhone = from phoneno in xelement.Elements("Employee")
                where (string)phoneno.Element("Phone").Attribute("Type") == "Home"
                select phoneno;
 
Console.WriteLine("List HomePhone Nos.");
foreach (XElement xEle in homePhone)
{
    Console.WriteLine(xEle.Element("Phone").Value);
}

نتیجه:

 

6 . چگونه می توان دسترسی به عناصر تو در تو (nested) پیدا نمود؟

همانگونه که در ابتدای مقاله بیان شد، عنصر آدرس حاوی عناصر داخلی تری به نام های Street، City، State،Zip، Country می باشد. اکنون قصد داریم مشخصات کارمندانی را برگردانیم که شهر (City) محل سکونت آن ها Alta باشد را چاپ کنیم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var addresses = from address in xelement.Elements("Employee")
                where (string)address.Element("Address").Element("City").Value == "Alta"
                select address;
 
Console.WriteLine("Details of Employees living in Alta City");
foreach (XElement xEle in addresses)
    Console.WriteLine(xEle);

نکته:

همانطور که ملاحظه می نمایید با استفاده ی مجدد از متد Element می توانیم به عناصر درونی تر هر عنصر دسترسی پیدا کنیم.

نتیجه:


 

7 . چگونه می توان کارمندان را بر اساس شناسه کارمندی (EmpId) به شکل نزولی مرتب نمود؟

این عمل را می توان همانند دستورات متداول LINQ انجام داد.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var sortedList = from employee in xelement.Elements("Employee")
                 orderby employee.Element("EmpId").Value descending
                 select employee;
 
Console.WriteLine("Sorted by EmpId descending");
foreach (XElement xEle in sortedList)
    Console.WriteLine(xEle);

 

8 . چگونه می توان به مشخصات دو نفر کارمندی که در ابتدای فایل XML قرار دارند دسترسی پیدا نمود؟

با استفاده از دستور Take این کار را انجام می دهیم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var emps = xelement.Elements("Employee").Take(2);
 
foreach (XElement xEle in emps)
    Console.WriteLine(xEle);

 

9 . چگونه می توان به مشخصات دومین و سومین کارمند دسترسی پیدا نمود.

با استفاده از ترکیب متدهای Take و Skip این کار را انجام می دهیم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var emps = xelement.Elements("Employee").Skip(1).Take(2);
 
foreach (XElement xEle in emps)
    Console.WriteLine(xEle);

 

10 . دسترسی به مشخصات دو کارمندی که در آخر فایل XML قرار دارند چگونه امکان پذیر می باشد؟

برای انجام این کار از متد Reverse که عملکرد آن معکوس نمودن محل قرار گیری عناصر یک دنباله (Sequence) می باشد به همراه متد Take استفاده نموده ایم.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var emps = xelement.Elements("Employee").Reverse().Take(2);
 
foreach (XElement xEle in emps)
    Console.WriteLine(xEle);

نتیجه:


نکته:

همانطور که ملاحظه می کنید با توجه به اینکه ما از متد Reverse استفاده نموده ایم، در خروجی ابتدا مشخصات کارمند چهارم و سپس کارمند سوم چاپ شده است. اگر نیاز دارید که ابتدا سوم و سپس چهارمی چاپ شود، کافیست که متد Reverse را مجددا فراخوانی نمایید.

XElement xelement = XElement.Load("..\\..\\Employees.xml");
 
var emps = xelement.Elements("Employee").Reverse().Take(2).Reverse();
 
foreach (XElement xEle in emps)
    Console.WriteLine(xEle);


در مقاله ی بعدی به تشریح نحوه ی انجام عملیات حذف و بروز رسانی و غیره بر روی اسناد XML خواهیم پرداخت.

سورس کامل کدهای این مقاله از لینک بالای صفحه قابل دریافت می باشد.

برگرفته از (همراه با تغییر و تصرف):  DotNetCurry