Поддръжка на XML библиотеки в Java

1. Въведение

В тази статия ще сравняваме Java XML библиотеки и API.

Това е втората статия от поредицата за поддръжката на Java за XML, ако искате да се задълбочите в поддръжката на XPath в Java, погледнете предишната статия.

2. Общ преглед

Сега ще се задълбочим в поддръжката на XML света и за това ще започнем, като обясним възможно най-просто всички инициали, свързани с темата.

В поддръжката на Java XML можем да намерим няколко дефиниции на API, като всяка има своите плюсове и минуси.

SAX : Това е API за анализ на събития, базиран на събития, осигурява достъп на ниско ниво, ефективна е паметта и е по-бърза от DOM, тъй като не зарежда цялото дърво на документа в паметта, но не осигурява поддръжка за навигация като тази, предоставена от XPath, въпреки че е по-ефективен, той е и по-труден за използване.

DOM : Той е базиран на модел парсер, който зарежда документ с дървовидна структура в паметта, така че имаме оригинален ред на елементите, можем да навигираме в нашия документ в двете посоки, той осигурява API за четене и запис, предлага XML манипулация и е много лесен за използване, въпреки че цената е силно натоварена върху ресурсите на паметта.

StAX : Той предлага лекотата на DOM и ефективността на SAX, но му липсват някои функционалности, предоставени от DOM като XML манипулация и ни позволява само да навигираме документа напред.

JAXB : Позволява ни да навигираме в документа в двете посоки, той е по-ефективен от DOM, позволява преобразуване от XML в типове Java и поддържа XML манипулация, но може да анализира само валиден XML документ.

Все още можете да намерите някои препратки към JAXP, но последното издание на този проект е от март 2013 г. и на практика е мъртво.

XML API таблица

3. XML

В този раздел ще видим най-популярните внедрения, за да можем да тестваме реални работещи мостри и да проверим разликите между тях.

В следващите примери ще работим с прост XML файл със структура като тази:

  Guava Introduction to Guava 04/04/2016 GuavaAuthor  ... 

4. DOM4J

Ще започнем, като разгледаме какво можем да направим с DOM4J и за този пример трябва да добавим последната версия на тази зависимост.

Това е една от най-популярните библиотеки за работа с XML файлове, тъй като ни позволява да извършваме двупосочно четене, да създаваме нови документи и да актуализираме съществуващите.

DOM4J може да работи с DOM , SAX , XPath и XLST . SAX се поддържа чрез JAXP .

Нека да разгледаме например, как можем да изберем филтриране на елемент по даден идентификатор.

SAXReader reader = new SAXReader(); Document document = reader.read(file); List elements = document.selectNodes("//*[@tutId='" + id + "']"); return elements.get(0);

Класът SAXReader е отговорен за създаването на DOM4J дърво от събития за синтактичен анализ на SAX . След като имаме org.dom4j.Document , просто трябва да извикаме необходимия метод и да му предадем израза XPath като низ.

Можем да заредим съществуващ документ, да направим промени в неговото съдържание и след това да актуализираме оригиналния файл.

for (Node node : nodes) { Element element = (Element)node; Iterator iterator = element.elementIterator("title"); while (iterator.hasNext()) { Element title =(Element)iterator.next(); title.setText(title.getText() + " updated"); } } XMLWriter writer = new XMLWriter( new FileWriter(new File("src/test/resources/example_updated.xml"))); writer.write(document); writer.close();

В горния пример променяме съдържанието на всяко заглавие и създаваме нов файл.

Забележете тук колко е лесно да получите възела на всяко заглавие в списък, като извикате elementIterator и предадете името на възела.

След като сме модифицирали нашето съдържание, ще използваме XMLWriter, който взема DOM4J дърво и го форматира в поток като XML .

Създаването на нов документ от нулата е толкова просто, колкото виждаме по-долу.

Document document = DocumentHelper.createDocument(); Element root = document.addElement("XMLTutorials"); Element tutorialElement = root.addElement("tutorial").addAttribute("tutId", "01"); tutorialElement.addAttribute("type", "xml"); tutorialElement.addElement("title").addText("XML with Dom4J"); ... OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter( new FileWriter(new File("src/test/resources/example_new.xml")), format); writer.write(document); writer.close(); 

DocumentHelper ни дава колекция от методи, които да използваме от DOM4J , като createDocument, който създава празен документ, за да започнем да работим с него.

Можем да създадем толкова атрибути или елементи, колкото ни е необходимо, с методите, предоставени от DOM4J , и след като завършим документа си, ние просто го записваме във файл, както направихме с случая на актуализация преди.

5. JDOM

За да работим с JDOM, трябва да добавим тази зависимост към нашия pom.

Стилът на работа на JDOM е доста подобен на този на DOM4J , така че ще разгледаме само няколко примера:

SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(this.getFile()); Element tutorials = doc.getRootElement(); List titles = tutorials.getChildren("tutorial"); 

В горния пример извличаме всички елементи от основния елемент по много прост начин, както можем да направим с DOM4J:

SAXBuilder builder = new SAXBuilder(); Document document = (Document) builder.build(file); String filter = "//*[@tutId='" + id + "']"; XPathFactory xFactory = XPathFactory.instance(); XPathExpression expr = xFactory.compile(filter, Filters.element()); List node = expr.evaluate(document);

Отново тук, в горния код, имаме SAXBuilder, създаващ екземпляр на документ от даден файл. Извличаме елемент от неговия атрибут tutId чрез предаване на XPath израз на XPathFactory, предоставен от JDOM2.

6. StAX

Сега ще видим как бихме могли да извлечем всички елементи от нашия корен елемент, използвайки API на Stax . Stax е включен в JDK от Java 6, така че не е нужно да добавяте зависимости.

Първо, трябва да създадем урок клас:

public class Tutorial { private String tutId; private String type; private String title; private String description; private String date; private String author; // standard getters and setters }

и тогава сме готови да следваме с:

List tutorials = new ArrayList(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(this.getFile())); Tutorial current; while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); switch (event.getEventType()) { case XMLStreamConstants.START_ELEMENT: StartElement startElement = event.asStartElement(); String qName = startElement.getName().getLocalPart(); ... break; case XMLStreamConstants.CHARACTERS: Characters characters = event.asCharacters(); ... break; case XMLStreamConstants.END_ELEMENT: EndElement endElement = event.asEndElement(); // check if we found the closing element // close resources that need to be explicitly closed break; } }

В горния пример, за да ни помогне да извлечем информацията, трябваше да създадем клас, в който да съхраняваме извлечените данни.

За да прочетем документа, декларирахме така наречените обработчици на събития и ги използвахме за навигация в нашия документ напред. Не забравяйте, че реализациите на SAX не осигуряват двупосочна навигация. Както можете да видите тук, трябва да се свърши много работа само за извличане на прост списък с елементи.

7. JAXB

JAXB is included with the JDK, as well as Xerces, se don't need any extra dependency for this one.

It's very simple to load, create and manipulate information from an XML file using JAXB.

We just need to create the correct java entities to bind the XML and that's it.

JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Tutorials tutorials = (Tutorials) jaxbUnmarshaller.unmarshal(this.getFile());

In the example above, we load our XML file into our object and from there we can handle everything as a normal Java structure;

To create a new document, it is as simple as reading it but doing the reverse way, like done in the below code.

Firstly, we are going to modify our Tutorial class to add JAXB annotations to getters and setters:

public class Tutorial { ... public String getTutId() { return tutId; } @XmlAttribute public void setTutId(String tutId) { this.tutId = tutId; } ... @XmlElement public void setTitle(String title) { this.title = title; } ... } @XmlRootElement public class Tutorials { private List tutorial; // standard getters and setters with @XmlElement annotation }

With @XmlRootElement we define what object is going to represent the root node of our document and then we use @XmlAttribute or @XmlElement to define whether that attribute represents an attribute of a node or an element of the document.

Then we can follow with:

Tutorials tutorials = new Tutorials(); tutorials.setTutorial(new ArrayList()); Tutorial tut = new Tutorial(); tut.setTutId("01"); ... tutorials.getTutorial().add(tut); JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); jaxbMarshaller.marshal(tutorials, file);

As you can see, binding XML file to Java objects is the easiest way to work this kind of files.

8. XPath Expression Support

To create complex XPath expressions, we can use Jaxen. This is an open source XPath library adaptable to many different object models, including DOM, XOM, DOM4J, and JDOM.

We can create XPath expressions and compile them against many supported documents.

String expression = "/tutorials/tutorial"; XPath path = new DOMXPath(expression); List result = path.selectNodes(xmlDocument);

To make it work we'll need to add this dependency to our project.

9. Conclusion

As you can see there are many options for working with XML, depending on the requirements of your application, you could work with any of them or you may have to choose between efficiency and simplicity.

You can find the full working samples for this article in our git repository here.