Этот учебник покажет вам, как использовать встроенный в 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(); Listresult; 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 Listresult = 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 Listresult = 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/”