Этот учебник покажет вам, как использовать встроенный в Java синтаксический анализатор SAX для чтения и анализа XML-файла.
- 1. Что такое простой API для XML (SAX)
- 2. Читать или анализировать XML-файл (SAX)
- 3. Преобразование XML-файла в объект
- 4. Обработчик ошибок SAX
- 5. Саксофон и Юникод
- 6. Скачать Исходный Код
- 7. Рекомендации
1. Что такое простой API для XML (SAX)
1.1 Простой API для XML (SAX) – это push-API и шаблон наблюдателя , управляемый событиями, последовательный доступ к элементам XML-файла последовательно. Этот синтаксический анализатор SAX считывает XML-файл от начала до конца, вызывает один метод при обнаружении одного элемента или вызывает другой метод при обнаружении определенного текста или атрибута.
SAX быстр и эффективен, требует гораздо меньше памяти, чем DOM, потому что SAX не создает внутреннее представление (древовидную структуру) XML-данных, как это делает DOM.
Примечание Синтаксический анализатор SAX работает быстрее и использует меньше памяти, чем анализатор DOM. SAX подходит для последовательного чтения XML-элементов; DOM подходит для манипуляций с XML, таких как создание, изменение или удаление XML-элементов.
1.2 Некоторые распространенные события САКСОФОНА:
Начальный документ()иКонечный документ()– Метод, вызываемый в начале и в конце XML-документа.Начальный элемент()иКонечный элемент()– Метод, вызываемый в начале и в конце XML-элемента.символы()– Метод, вызываемый с текстовым содержимым между началом и концом XML-элемента.
1.3 Ниже приведен простой XML-файл.
mkyong
Анализатор SAX считывает приведенный выше XML-файл и последовательно вызывает следующие события или методы:
Начальный документ()Элемент запуска()–<имя>символы()–mkyongКонечный элемент()–конечный документ()
2. Читать или анализировать XML-файл (SAX)
В этом примере показано, как использовать встроенные в Java API-интерфейсы SAX-анализатора для чтения или анализа XML-файла.
2.1 Ниже приведен XML-файл.
mkyong support 5000 yflow admin 8000
P.S В XML-файле для таких специальных символов, как < или & , нам нужно обернуть его CDATA-ДАННЫЕ .
2.2 Создайте класс для расширения org.xml.sax.помощники. DefaultHandler и переопределите методы startElement , endElement и символов для печати всех XML-элементов, атрибутов, комментариев и текстов.
package com.mkyong.xml.sax.handler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class PrintAllHandlerSax extends DefaultHandler {
private StringBuilder currentValue = new StringBuilder();
@Override
public void startDocument() {
System.out.println("Start Document");
}
@Override
public void endDocument() {
System.out.println("End Document");
}
@Override
public void startElement(
String uri,
String localName,
String qName,
Attributes attributes) {
// reset the tag value
currentValue.setLength(0);
System.out.printf("Start Element : %s%n", qName);
if (qName.equalsIgnoreCase("staff")) {
// get tag's attribute by name
String id = attributes.getValue("id");
System.out.printf("Staff id : %s%n", id);
}
if (qName.equalsIgnoreCase("salary")) {
// get tag's attribute by index, 0 = first attribute
String currency = attributes.getValue(0);
System.out.printf("Currency :%s%n", currency);
}
}
@Override
public void endElement(String uri,
String localName,
String qName) {
System.out.printf("End Element : %s%n", qName);
if (qName.equalsIgnoreCase("name")) {
System.out.printf("Name : %s%n", currentValue.toString());
}
if (qName.equalsIgnoreCase("role")) {
System.out.printf("Role : %s%n", currentValue.toString());
}
if (qName.equalsIgnoreCase("salary")) {
System.out.printf("Salary : %s%n", currentValue.toString());
}
if (qName.equalsIgnoreCase("bio")) {
System.out.printf("Bio : %s%n", currentValue.toString());
}
}
// http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html#characters%28char%5B%5D,%20int,%20int%29
// SAX parsers may return all contiguous character data in a single chunk,
// or they may split it into several chunks
@Override
public void characters(char ch[], int start, int length) {
// The characters() method can be called multiple times for a single text node.
// Some values may missing if assign to a new string
// avoid doing this
// value = new String(ch, start, length);
// better append it, works for single or multiple calls
currentValue.append(ch, start, length);
}
}
2.3 SAXParser для анализа XML-файла.
package com.mkyong.xml.sax;
import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
public class ReadXmlSaxParser {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = factory.newSAXParser();
PrintAllHandlerSax handler = new PrintAllHandlerSax();
saxParser.parse(FILENAME, handler);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
Выход
Start Document Start Element : Company Start Element : staff Staff id : 1001 Start Element : name End Element : name Name : mkyong Start Element : role End Element : role Role : support Start Element : salary Currency :USD End Element : salary Salary : 5000 Start Element : bio End Element : bio Bio : HTML tag testing End Element : staff Start Element : staff Staff id : 1002 Start Element : name End Element : name Name : yflow Start Element : role End Element : role Role : admin Start Element : salary Currency :EUR End Element : salary Salary : 8000 Start Element : bio End Element : bio Bio : a & b End Element : staff End Element : Company End Document
3. Преобразование XML-файла в объект
В этом примере анализируется XML-файл и преобразуется в Список объектов. Это работает, но не рекомендуется, попробуйте ДЖАКСБ
3.1 Просмотрите тот же XML-файл.
mkyong support 5000 yflow admin 8000
3.2 И мы хотим преобразовать приведенный выше XML-файл в следующий объект Персонал .
package com.mkyong.xml.sax.model;
import java.math.BigDecimal;
public class Staff {
private Long id;
private String name;
private String role;
private BigDecimal salary;
private String Currency;
private String bio;
//... getters, setters...toString
}
3.3 Приведенный ниже класс выполнит преобразование XML в объект.
package com.mkyong.xml.sax.handler;
import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class MapStaffObjectHandlerSax extends DefaultHandler {
private StringBuilder currentValue = new StringBuilder();
List result;
Staff currentStaff;
public List getResult() {
return result;
}
@Override
public void startDocument() {
result = new ArrayList<>();
}
@Override
public void startElement(
String uri,
String localName,
String qName,
Attributes attributes) {
// reset the tag value
currentValue.setLength(0);
// start of loop
if (qName.equalsIgnoreCase("staff")) {
// new staff
currentStaff = new Staff();
// staff id
String id = attributes.getValue("id");
currentStaff.setId(Long.valueOf(id));
}
if (qName.equalsIgnoreCase("salary")) {
// salary currency
String currency = attributes.getValue("currency");
currentStaff.setCurrency(currency);
}
}
public void endElement(String uri,
String localName,
String qName) {
if (qName.equalsIgnoreCase("name")) {
currentStaff.setName(currentValue.toString());
}
if (qName.equalsIgnoreCase("role")) {
currentStaff.setRole(currentValue.toString());
}
if (qName.equalsIgnoreCase("salary")) {
currentStaff.setSalary(new BigDecimal(currentValue.toString()));
}
if (qName.equalsIgnoreCase("bio")) {
currentStaff.setBio(currentValue.toString());
}
// end of loop
if (qName.equalsIgnoreCase("staff")) {
result.add(currentStaff);
}
}
public void characters(char ch[], int start, int length) {
currentValue.append(ch, start, length);
}
}
3.4 Запустите его.
package com.mkyong.xml.sax;
import com.mkyong.xml.sax.handler.MapStaffObjectHandlerSax;
import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ReadXmlSaxParser2 {
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try (InputStream is = getXMLFileAsStream()) {
SAXParser saxParser = factory.newSAXParser();
// parse XML and map to object, it works, but not recommend, try JAXB
MapStaffObjectHandlerSax handler = new MapStaffObjectHandlerSax();
saxParser.parse(is, handler);
// print all
List result = handler.getResult();
result.forEach(System.out::println);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
// get XML file from resources folder.
private static InputStream getXMLFileAsStream() {
return ReadXmlSaxParser2.class.getClassLoader().getResourceAsStream("staff.xml");
}
}
Выход
Staff{id=1001, name='揚木金', role='support', salary=5000, Currency='USD', bio='HTML tag testing'}
Staff{id=1002, name='yflow', role='admin', salary=8000, Currency='EUR', bio='a & b'}
4. Обработчик ошибок SAX
В этом примере показано, как зарегистрировать пользовательский обработчик ошибок для синтаксического анализатора SAX.
4.1 Создайте класс и расширяйте org.xml.саксофон. Обработчик ошибок . Прочитайте код для самоописания. Он просто завернул исходное сообщение об ошибке.
package com.mkyong.xml.sax.handler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.PrintStream;
public class CustomErrorHandlerSax implements ErrorHandler {
private PrintStream out;
public CustomErrorHandlerSax(PrintStream out) {
this.out = out;
}
private String getParseExceptionInfo(SAXParseException spe) {
String systemId = spe.getSystemId();
if (systemId == null) {
systemId = "null";
}
String info = "URI=" + systemId + " Line="
+ spe.getLineNumber() + ": " + spe.getMessage();
return info;
}
public void warning(SAXParseException spe) throws SAXException {
out.println("Warning: " + getParseExceptionInfo(spe));
}
public void error(SAXParseException spe) throws SAXException {
String message = "Error: " + getParseExceptionInfo(spe);
throw new SAXException(message);
}
public void fatalError(SAXParseException spe) throws SAXException {
String message = "Fatal Error: " + getParseExceptionInfo(spe);
throw new SAXException(message);
}
}
4.2 Мы используем SAXParser.getxmlreader() для получения org.xml.sax. XmlReader , он предоставляет больше возможностей для настройки синтаксического анализатора SAX.
package com.mkyong.xml.sax;
import com.mkyong.xml.sax.handler.CustomErrorHandlerSax;
import com.mkyong.xml.sax.handler.MapStaffObjectHandlerSax;
import com.mkyong.xml.sax.model.Staff;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ReadXmlSaxParser3 {
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try (InputStream is = getXMLFileAsStream()) {
SAXParser saxParser = factory.newSAXParser();
// parse XML and map to object, it works, but not recommend, try JAXB
MapStaffObjectHandlerSax handler = new MapStaffObjectHandlerSax();
// try XMLReader
//saxParser.parse(is, handler);
// more options for configuration
XMLReader xmlReader = saxParser.getXMLReader();
// set our custom error handler
xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err));
xmlReader.setContentHandler(handler);
InputSource source = new InputSource(is);
xmlReader.parse(source);
// print all
List result = handler.getResult();
result.forEach(System.out::println);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
// get XML file from resources folder.
private static InputStream getXMLFileAsStream() {
return ReadXmlSaxParser2.class.getClassLoader().getResourceAsStream("staff.xml");
}
}
4.3 Обновить staff.xml , удалите CDATA в элементе bio и поместите & , и анализатор SAX выдаст ошибку.
mkyong support 5000 &
4.4 Запустите его с помощью описанного выше пользовательского обработчика ошибок.
xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err));
Выход
org.xml.sax.SAXException: Fatal Error: URI=null Line=8: The entity name must immediately follow the '&' in the entity reference. at com.mkyong.xml.sax.handler.CustomErrorHandlerSax.fatalError(CustomErrorHandlerSax.java:41) at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:181) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327) at java.xml/com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1471) //...
4.5 Запустите его без специального обработчика ошибок.
// xmlReader.setErrorHandler(new CustomErrorHandlerSax(System.err));
Выход
[Fatal Error] :8:15: The entity name must immediately follow the '&' in the entity reference. org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 15; The entity name must immediately follow the '&' in the entity reference. at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1243) at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635) at com.mkyong.xml.sax.ReadXmlSaxParser2.main(ReadXmlSaxParser2.java:44)
5. Саксофон и Юникод
Для XML-файлов, содержащих символы Юникода, по умолчанию SAX может следовать кодировке XML (по умолчанию UTF-8) и правильно анализировать содержимое.
5.1 Мы можем определить кодировку в верхней части XML-файла, encoding="кодировка-код" ; например, ниже приведен XML-файл, использующий кодировку UTF-8 .
揚木金 support 5000 yflow admin 8000
5.2 В качестве альтернативы мы можем определить указанную кодировку в Источнике ввода .
XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(handler); InputSource source = new InputSource(is); // set encoding source.setEncoding(StandardCharsets.UTF_8.toString()); //source.setEncoding(StandardCharsets.UTF_16.toString()); xmlReader.parse(source);
Примечание Дополнительные примеры синтаксического анализатора SAX – Oracle – Простой API для XML (SAX)
6. Скачать Исходный Код
$клон git $клон git
$компакт-диск java-xml
$cd src/основной/java/com/mkyong/xml/саксофон/
7. Рекомендации
- Википедия – Java API для обработки XML
- Википедия – Простой API для XML
- Википедия – Объектная модель документа
- Википедия – Шаблон наблюдателя
- Oracle – Java API для обработки XML (JAXP)
- Oracle – Простой API для XML (SAX)
- Объектная модель Oracle –Документа (DOM)
- Как читать XML–файл на Java – (DOM-анализатор)
- Как читать XML–файл на Java – (синтаксический анализатор JDOM)
- Пример JAXB привет, мир
Оригинал: “https://mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/”