خواندن فایل های XML با SAX Parser

در این آموزش با خواندن فایل های XML با روش مبتنی بر SAX آشنا می شویم. قبل از هر کار یک فایل xml جدید به نام sample.xml در درایو D ایجاد می کنیم و محتوای زیر را در آن می نویسیم :

<?xml version="1.0" encoding="utf-8" ?>
<Persons>
  <Person name="John Smith">
    <Age>30</Age>
    <Gender>Male</Gender>
  </Person>
  <Person name="Mike Folley">
    <Age>25</Age>
    <Gender>Male</Gender>
  </Person>
  <Person name="Lisa Carter">
    <Age>22</Age>
    <Gender>Female</Gender>
  </Person>
  <Person name="Jerry Frost">
    <Age>27</Age>
    <Gender>Male</Gender>
  </Person>
  <Person name="Adam Wong">
    <Age>35</Age>
    <Gender>Male</Gender>
  </Person>
</Persons>

این فایل یک فایل xml ساده است که تگ ریشه آن Persons است. در داخل این تگ یک تگ Person و در داخل این تک نیز دو تگ Age و Gender قرار دارند. روش مبتنی بر SAX اگرچه سریعتر است ولی برای خواندن درست نیاز داریم که یک Handler برای تعبیر تگ ها و المان ها ایجاد کنیم ، برای این کار یک کلاس جدید به نام MyHandler ایجاد می کنیم و کد زیر را در آن می نویسیم (خطوط 45-9) :

   1: import org.xml.sax.Attributes;
   2: import org.xml.sax.SAXException;
   3: import org.xml.sax.helpers.DefaultHandler;
   4: 
   5: import java.io.File;
   6: import javax.xml.parsers.SAXParser;
   7: import javax.xml.parsers.SAXParserFactory;
   8: 
   9: class MyHandler extends DefaultHandler 
  10: {
  11:     boolean Age = false;
  12:     boolean Gender = false;
  13: 
  14:     @Override
  15:     public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException 
  16:     {
  17:         if (qName.equalsIgnoreCase("Person")) {
  18:             System.out.println("Person Name: " + attr.getValue("name"));
  19: 
  20:         }
  21:         else if (qName.equalsIgnoreCase("Age")) {
  22:             Age = true;
  23:         }
  24:         else if (qName.equalsIgnoreCase("Gender")) {
  25:             Gender = true;
  26:         }
  27:     }
  28: 
  29:     @Override
  30:     public void characters(char[] ch, int start, int length) throws SAXException 
  31:     {
  32:         if (Age) 
  33:         {
  34:             System.out.println("Person Age: " + new String(ch, start, length));
  35:         }
  36:         else if (Gender) 
  37:         {
  38:             System.out.println("Person Gender: " + new String(ch, start, length));
  39:             System.out.println("----------------");
  40:         }
  41: 
  42:         Age = false;
  43:         Gender = false;
  44:     }
  45: }
  46: 
  47: public class XMLSaxRead 
  48: {
  49:     public static void main(String[] args) throws Exception 
  50:     {
  51:         File myXMLFile = new File("D:/sample.xml");
  52: 
  53:         SAXParserFactory sFactory = SAXParserFactory.newInstance();
  54: 
  55:         SAXParser saxParser = sFactory.newSAXParser();
  56: 
  57:         MyHandler mHandler = new MyHandler();
  58: 
  59:         saxParser.parse(myXMLFile, mHandler);
  60:     }
  61: }
Person Name: John Smith
Person Age: 30
Person Gender: Male
----------------
Person Name: Mike Folley
Person Age: 25
Person Gender: Male
----------------
Person Name: Lisa Carter
Person Age: 22
Person Gender: Female
----------------
Person Name: Jerry Frost
Person Age: 27
Person Gender: Male
----------------
Person Name: Adam Wong
Person Age: 35
Person Gender: Male
----------------

کلاس MyHandler زیر کلاس DefaultHander است و برای کار بار آن باید حداقل دو متد ()startElement و ()characters را override کنیم. در هنگام تجزیه استریمی از این هندلر استفاده شده و در هر زمان که عمل تجزیه به یک تگ آغازین می رسد متد ()startElement فراخوانی می شود و هر گاه که تجزیه گر وارد قسمت های متنی داخل یک تگ (مثلاً Male در تگ Gender) می شود متد characters فراخوانی می شود. پس با توجه به موارد فوق متد های ()startElement و ()characters را به صورتی که در کد بالا مشاهده می کنید، پیاده سازی می کنیم(خطوط 44-15).
در داخل متد ()startElement با استفاده از پارامتر qName می توانیم نام گره را مشخص کنیم، اگر نام گره person بود مقدار صفت id را چاپ می کنیم، پارامتر attr در هر گره صفت های گره را نگه داری می کند که با فراخوانی متد ()getValue بر روی آن می توانیم به یک صفت خاص دسترسی پیدا کنیم ، در خط زیر به صفت id دسترسی پیدا می کنیم و مقدار آن را چاپ می کنیم. اگر تگی که وارد آن می شویم Person نباشد یکی از دو if بعدی ممکن است اجرا شوند :

  • اگر نام تگ Age باشد مقدار بولی Age را برابر true قرار می دهیم.
  • اگر نام تگ Gender باشد مقدار بولی Gender را برابر true قرار می دهیم.

می دانیم که متد ()character بعد از متد ()startElement فراخوانی می شود (زیرا ابتدا یک تگ باز می شود ، متن در داخل آن قرار می گیرد و سپس تگ بسته می شود مثل <Gender>Male</Gender>). پس هنگامی که وارد متد character می شویم. تنها یکی از موارد Age یا Gender می تواند برابر با true باشد. با استفاده از ساختار شرطی خطوط 40-32 مورد برابر با true را پیدا می کنیم و متن داخل آن را چاپ می کنیم.

در پایان تمام متغیر های بولی را برابر با false قرار می دهیم(خطوط 42 و 43). می دانیم که با رسیدن به تگ آغازین بعدی مجدداً متد ()startElement فراخوانی می شود و مجدداً موارد فوق تکرار می شود. حال که Handler مان آماده است می توانیم کد لازم برای خواندن و تجزیه فایل xml را بنویسیم(خطوط 59-51). در این خطوط ، یک SAXParser ایجاد می کنیم و فایل و هندلر مورد نظر را به آن می دهیم، مابقی کار ها به عهده تجزیه گر خواهد بود.