السلام عليكم،
الSAX أو Simple API for XML، هي API توفرها الجافا لقراءة المستندات xml.
- الفرق بين SAX و DOM API
- كيف يتم التنصت على أحداث الSAX
- كتابة الفئة التي ستتنصت على الأحداث
- الفئة XMLReader
- البرنامج بأكمله
- استرجاع قيمة عنصر ما
*******************************************************************************************
الفرق بين SAX و DOM API
الحزمتين SAX و DOM لهما نفس الهدف، وهو قراءة المستندات xml، لكن الوسيلة هي التي تختلف، وهذا هو ما يحدد اي حزمة سنستعمل.
في حالة DOM، فإنه يتم عمل parsing للمستند وإنشاء شجرة tree في الذاكرة تمثل المستند xml، ميزة هذه الطريقة انها تسمح لنا ب random-access، أي أننا نستطيع استرجاع أي معلومة من أي عنصر في المستند في أي وقت. عيب هذه الطريقة هو أنها تستهلك موارد كبيرة من الذاكرة إذا كان المستند xml كبير الحجم.
الSAX يعتبر event-based API، هذا يعني أنه يكتفي فقط بإرسال أحداث إلى البرنامج، ولا يخزن أي شيء، وبالتالي فهو لا يحتاج لموارد كبيرة من الذاكرة، لكنه وبخلاف DOM لا يتيح random-access لعناصر المستند xml، فهو يمر مرة واحدة على كل عنصر ما حسب ترتيبه في المستند، وبعد ذلك لا يمكن العودة إليه، لذلك يتوجب على المبرمج أن يخزن قيمة العناصر التي يحتاج.
لمزيد من المعلومات حول الفرق بين SAX و DOM
http://www.w3.org/DO....html#SAXandDOM
كيف يتم التنصت على أحداث الSAX
بما أن SAX يعتبر event-based، فيلزمنا فئة تقوم بالتنصت على هاته الأحداث، وتنفيذ العمليات التي نريد عند كل حدث. هذه الفئة يجب أن تعمل implement للinterface ContentHandler، هاته الأخيرة تحتوي على عدة طرق، كل واحدة منها تمثل حدثا SAX، من أهم هاته الطرق نجد startDocument، endDocument، startElement، endElement، characters
void startDocument() throws SAXException
هاته الطريقة يتم تنفيذها عند بداية المستند
void endDocument() throws SAXException
هاته الطريقة يتم تنفيذها عند نهاية المستند
void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
هاته الطريقة يتم تنفيذها عند بداية كل عنصر (node) من المستند.
- المعطى "uri" يمثل مسار الnamespace الذي ينتمي له العنصر، في حالة لم يكن ينتمي لأي namespace، فإن المعطى يكون جملة فارغة.
- المعطى "localName" يمثل إسم العنصر.
- المعطى "qName" يمثل إسم العنصر بالإضافة إلى الprefix الخاص بالnamespace، في حالة لم يكن ينتمي لأي namespace، فإن المعطى يكون جملة فارغة.
- المعطى "atts" يمثل الattributes المرتبطة بهذا العنصر.
void endElement(String uri, String localName, String qName) throws SAXException
هاته الطريقة يتم تنفيذها عند نهاية كل عنصر.
public void characters(char[] ch, int start, int length) throws SAXException
هاته الطريقة يتم تنفيذها عند العثور على أي نص.
كتابة الفئة التي ستتنصت على الأحداث
لتسهيل الأمر، لن نقوم بعمل implement لContentHandler، لكننا سنرث من فئة تقوم بذلك، وهي DefaultHandler، وهكذا سنكتب فقط الطرق التي نريد استعمالها.
class MyHandler extends DefaultHandler {
@Override
public void startDocument() throws SAXException {
System.out.println("Start document.");
}
@Override
public void endDocument() throws SAXException {
System.out.println("End document.");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("Start element " + localName +".");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("End element " + localName +".");
}
}الفئة XMLReader
هاته الفئة هي الparser، فهي التي تقرأ المستند xml، وهي أيضا التي ترسل الأحداث SAX، وبالتالي سنريطها مع الفئة MyHandler التي كتبنا والتي تتنصت على هاته الأحداث.
لإنشاء كائن XMLReader ننادي على الطريقة
XMLReaderFactory.createXMLReader();
لربط هذا الكائن بالفئة التي تتنصت على الأحداث، نستعمل الطريقة
setContentHandler (ContentHandler handler)
وأخيرا نبدأ بقراءة المستند xml بواسطة الطريقة parse التي نمرر لها مسار المستند xml
parse (String systemId) throws IOException, SAXException
البرنامج بأكمله
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class TestSAX {
public static void main(String[] args) {
try {
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(new MyHandler());
reader.parse("addressbook.xml");
} catch (IOException ex) {
ex.printStackTrace();
} catch (SAXException ex) {
ex.printStackTrace();
}
}
}
class MyHandler extends DefaultHandler {
@Override
public void startDocument() throws SAXException {
System.out.println("Start document.");
}
@Override
public void endDocument() throws SAXException {
System.out.println("End document.");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("Start element " + localName +".");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("End element " + localName +".");
}
}والمستند addressbook.xml
<?xml version="1.0" encoding="UTF-8"?> <phonebook> <person category="friend"> <name>Ahmed</name> <age>23</age> <sexe>male</sexe> <phone>0522222222</phone> <address>182 rue yyy</address> </person> <person category="friend"> <name>Sophia</name> <age>24</age> <sexe>female</sexe> <phone>0522333333</phone> <address>16 yyy street</address> </person> <person category="neighbour"> <name>Ali</name> <age>30</age> <sexe>male</sexe> <phone>0640444444</phone> <address>172 rue yyy</address> </person> <person category="neighbour"> <name>Samir</name> <age>28</age> <sexe>male</sexe> <phone>0660666666</phone> <address>180 rue yyy</address> </person> </phonebook>
لا بد أنكم لاحظتم أنه لا توجد أي طريقة مباشرة لاسترجاع محتوى كل عنصر. ذلك لان المحتوى يعتبر كنص، وبالتالي فيمكننا استرجاعه في الطريقة characters التي سبق وأشرنا إليها، لكن يجب قبل ذلك معرفة إلى أي عنصر ينتمي هذا النص، لانه لا توجد وسيلة مباشرة لمعرفة ذلك داخل الطريقة characters.
استرجاع قيمة عنصر ما
الفكرة بسيطة، وهي أننا سنقوم بتخزين إسم العنصر الحالي داخل الطريقة startElement في متغير، نسميه مثلا currentElement، وداخل الطريقة characters، نتحقق من قيمة المتغير، فإذا كان يساوي العنصر الذي نريده، فإننا نسترجع النص الذي تم تمريره إلى الطريقة characters.
نقوم أولا بالإعلان عن المتغير currentElement
private String currentElement;
داخل الطريقة startElement نقوم بتخزين إسم العنصر الحالي
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("Start element " + localName +".");
currentElement = localName;
}وداخل الطريقة endElement، نجعل قيمة currentElement مساوية ل null، لأننا خرجنا من العنصر
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("End element " + localName +".");
currentElement = null;
}وفي الطريقة characters، نقوم بالتحقق من قيمة المتغير currentElement، ونقوم بالعمل الذي نريد حسب العنصر الحالي، في المثال نقوم فقط بكتابة إسم كل شخص
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String value = new String(ch, start, length);
if ("name".equals(currentElement)) {
System.out.println("Name: " + value);
}
}البرنامج بعد التعديل:
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class TestSAX {
public static void main(String[] args) {
try {
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setContentHandler(new MyHandler());
reader.parse("addressbook.xml");
} catch (IOException ex) {
ex.printStackTrace();
} catch (SAXException ex) {
ex.printStackTrace();
}
}
}
class MyHandler extends DefaultHandler {
private String currentElement;
@Override
public void startDocument() throws SAXException {
System.out.println("Start document.");
}
@Override
public void endDocument() throws SAXException {
System.out.println("End document.");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("Start element " + localName +".");
currentElement = localName;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("End element " + localName +".");
currentElement = null;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String value = new String(ch, start, length);
if ("name".equals(currentElement)) {
System.out.println("Name: " + value);
}
}
}

