مثال محلل SAX في جافا

محلل SAX في جافا يوفر واجهة برمجة التطبيقات لتحليل مستندات XML. المحلل SAX مختلف عن محلل DOM لأنه لا يقوم بتحميل المستند XML كاملاً في الذاكرة وقراءة مستند XML بتسلسل.

محلل SAX

javax.xml.parsers.SAXParser توفر طريقة لتحليل مستند XML باستخدام معالجات الأحداث. تنفيذ هذه الفئة لواجهة XMLReader وتوفير نسخ محملة من أساليب parse() لقراءة مستند XML من ملف، InputStream، SAX InputSource و String URI. يتم تنفيذ التحليل الفعلي بواسطة فئة المعالج. نحتاج إلى إنشاء فئة معالج خاصة بنا لتحليل مستند XML. نحتاج إلى تنفيذ واجهة org.xml.sax.ContentHandler لإنشاء فئات معالج خاصة بنا. تحتوي هذه الواجهة على أساليب رد الاتصال التي تتلقى إشعارًا عند حدوث حدث. على سبيل المثال StartDocument، EndDocument، StartElement، EndElement، CharacterData الخ. org.xml.sax.helpers.DefaultHandler يوفر تنفيذًا افتراضيًا لواجهة ContentHandler ويمكننا توسيع هذه الفئة لإنشاء معالج خاص بنا. من النصح بتوسيع هذه الفئة لأنه قد نحتاج فقط إلى بعض الأساليب لتنفيذ. توسيع هذه الفئة سيحافظ على نظافة وصيانة الكود الخاص بنا.

مثال محلل SAX

لنقفز إلى برنامج مثال محلل SAX الآن، سأشرح الميزات المختلفة بالتفصيل لاحقًا. employees.xml

<?xml version="1.0" encoding="UTF-8"?>
<Employees>
	<Employee id="1">
		<age>29</age>
		<name>Pankaj</name>
		<gender>Male</gender>
		<role>Java Developer</role>
	</Employee>
	<Employee id="2">
		<age>35</age>
		<name>Lisa</name>
		<gender>Female</gender>
		<role>CEO</role>
	</Employee>
	<Employee id="3">
		<age>40</age>
		<name>Tom</name>
		<gender>Male</gender>
		<role>Manager</role>
	</Employee>
	<Employee id="4">
		<age>25</age>
		<name>Meghna</name>
		<gender>Female</gender>
		<role>Manager</role>
	</Employee>
</Employees>

لذلك لدينا ملف XML مخزن في نظام الملفات في مكان ما ، ومن خلال النظر إليه ، يمكننا الاستنتاج من أنه يحتوي على قائمة من الموظفين. كل موظف لديه سمة “id” وحقول “العمر” و “الاسم” و “الجنس” و “الدور”. سنستخدم محلل SAX لتحليل هذا الـ XML وإنشاء قائمة من كائنات الموظفين. هنا هو كائن الموظف الذي يمثل عنصر الموظف من XML.

package com.journaldev.xml;

public class Employee {
    private int id;
    private String name;
    private String gender;
    private int age;
    private String role;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }
    
    @Override
    public String toString() {
        return "Employee:: ID="+this.id+" Name=" + this.name + " Age=" + this.age + " Gender=" + this.gender +
                " Role=" + this.role;
    }
    
}

لنقم بإنشاء فئة معالج SAX الخاصة بنا ممتدة من فئة DefaultHandler.


package com.journaldev.xml.sax;

import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.journaldev.xml.Employee;

public class MyHandler extends DefaultHandler {

	// قائمة لاحتواء كائنات الموظفين
	private List empList = null;
	private Employee emp = null;
	private StringBuilder data = null;

	// طريقة الحصول على قائمة الموظفين
	public List getEmpList() {
		return empList;
	}

	boolean bAge = false;
	boolean bName = false;
	boolean bGender = false;
	boolean bRole = false;

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

		if (qName.equalsIgnoreCase("Employee")) {
			// إنشاء موظف جديد ووضعه في الخريطة
			String id = attributes.getValue("id");
			// تهيئة كائن الموظف وتعيين سمة "id"
			emp = new Employee();
			emp.setId(Integer.parseInt(id));
			// تهيئة القائمة
			if (empList == null)
				empList = new ArrayList<>();
		} else if (qName.equalsIgnoreCase("name")) {
			// تعيين القيم البوليانية للحقول ، وسيتم استخدامها في تعيين متغيرات الموظف
			bName = true;
		} else if (qName.equalsIgnoreCase("age")) {
			bAge = true;
		} else if (qName.equalsIgnoreCase("gender")) {
			bGender = true;
		} else if (qName.equalsIgnoreCase("role")) {
			bRole = true;
		}
		// إنشاء حاوية البيانات
		data = new StringBuilder();
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (bAge) {
			// عنصر العمر ، تعيين عمر الموظف
			emp.setAge(Integer.parseInt(data.toString()));
			bAge = false;
		} else if (bName) {
			emp.setName(data.toString());
			bName = false;
		} else if (bRole) {
			emp.setRole(data.toString());
			bRole = false;
		} else if (bGender) {
			emp.setGender(data.toString());
			bGender = false;
		}
		
		if (qName.equalsIgnoreCase("Employee")) {
			// إضافة كائن الموظف إلى القائمة
			empList.add(emp);
		}
	}

	@Override
	public void characters(char ch[], int start, int length) throws SAXException {
		data.append(new String(ch, start, length));
	}
}

تحتوي MyHandler على قائمة لكائنات Employee كحقل مع طريقة الحصول فقط. يتم إضافة كائنات Employee في أساليب معالجة الأحداث. أيضًا ، لدينا حقل موظف سيتم استخدامه لإنشاء كائن موظف وبمجرد تعيين جميع الحقول ، يتم إضافته إلى قائمة الموظفين.

أساليب محلل SAX للتجاوز عليها

الأساليب المهمة للتجاوز هي startElement()، endElement() و characters(). تبدأ SAXParser التحليل عند العثور على أي عنصر بداية، يتم استدعاء الطريقة startElement(). نقوم بتجاوز هذه الطريقة لتعيين المتغيرات البوليانية التي ستُستخدم لتحديد العنصر. نستخدم أيضًا هذه الطريقة لإنشاء كائن Employee جديد في كل مرة يتم فيها العثور على عنصر بداية Employee. تحقق كيفية قراءة السمة id هنا لتعيين حقل الكائن Employee id. يتم استدعاء الطريقة characters() عندما يتم العثور على بيانات حرفية بواسطة SAXParser داخل عنصر. لاحظ أن محلل SAX قد يقسم البيانات إلى شظايا متعددة ويستدعي الطريقة characters() عدة مرات (اقرأ وثائق طريقة characters() في فئة ContentHandler). لهذا السبب نستخدم StringBuilder للحفاظ على هذه البيانات باستخدام طريقة append(). endElement() هو المكان الذي نستخدم فيه بيانات StringBuilder لتعيين خصائص كائن الموظف وإضافة كائن Employee إلى القائمة كلما وجدنا علامة نهاية Employee. فيما يلي برنامج الاختبار الذي يستخدم MyHandler لتحليل XML أعلاه إلى قائمة من كائنات Employee.

package com.journaldev.xml.sax;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import com.journaldev.xml.Employee;

public class XMLParserSAX {

    public static void main(String[] args) {
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    try {
        SAXParser saxParser = saxParserFactory.newSAXParser();
        MyHandler handler = new MyHandler();
        saxParser.parse(new File("/Users/pankaj/employees.xml"), handler);
        // الحصول على قائمة الموظفين
        List empList = handler.getEmpList();
        // طباعة معلومات الموظف
        for(Employee emp : empList)
            System.out.println(emp);
    } catch (ParserConfigurationException | SAXException | IOException e) {
        e.printStackTrace();
    }
    }

}

إليك ناتج البرنامج أعلاه.

Employee:: ID=1 Name=Pankaj Age=29 Gender=Male Role=Java Developer
Employee:: ID=2 Name=Lisa Age=35 Gender=Female Role=CEO
Employee:: ID=3 Name=Tom Age=40 Gender=Male Role=Manager
Employee:: ID=4 Name=Meghna Age=25 Gender=Female Role=Manager

SAXParserFactory يوفر طرقًا مصنعية للحصول على مثيل SAXParser. نمرر كائن الملف إلى طريقة الفحص بالإضافة إلى مثيل MyHandler للتعامل مع أحداث الاستدعاء. محلل SAXParser مربك قليلاً في البداية ولكن إذا كنت تعمل على مستند XML كبير، فإنه يوفر طريقة أكثر كفاءة لقراءة XML من DOM Parser. هذا كل شيء بخصوص SAX Parser في Java.

يمكنك تنزيل المشروع من مستودع GitHub الخاص بنا.

المرجع: SAXParser، DefaultHandler

Source:
https://www.digitalocean.com/community/tutorials/java-sax-parser-example