1. 序章

この記事では、JavaXMLライブラリとAPIを比較します。

これは、XMLのJavaサポートに関するシリーズの2番目の記事です。JavaでのXPathサポートについて詳しく知りたい場合は、前の記事を参照してください。

2. 概要

次に、XMLの世界でのサポートをさらに深く掘り下げます。そのために、主題に関連するすべてのイニシャルをできるだけ簡単に説明することから始めます。

Java XMLサポートでは、いくつかのAPI定義を見つけることができ、それぞれに長所と短所があります。

SAX:これはイベントベースの解析APIであり、低レベルのアクセスを提供し、ドキュメントツリー全体をメモリにロードしないため、メモリ効率が高く、DOMよりも高速ですが、サポートは提供しません。 XPathが提供するようなナビゲーションの場合、より効率的ですが、使用するのも難しくなります。

DOM:ツリー構造ドキュメントをメモリにロードするモデルベースのパーサーとして、元の要素の順序があり、ドキュメントを双方向にナビゲートでき、読み取りと書き込みのAPIを提供します。 XML操作とそれは非常に使いやすいですが、価格はメモリリソースに大きな負担をかけます。

StAX:DOMの使いやすさとSAXの効率を提供しますが、XML操作などのDOMによって提供される機能が不足しており、ドキュメントを前方にナビゲートすることしかできません。

JAXB:ドキュメントを両方向にナビゲートでき、DOMよりも効率的で、XMLからJavaタイプへの変換が可能で、XML操作をサポートしますが、有効なXMLドキュメントのみを解析できます。

JAXPへの参照はまだいくつかありますが、このプロジェクトの最後のリリースは2013年3月からのものであり、事実上廃止されています。

XMLAPIテーブル

3. XML

このセクションでは、最も一般的な実装を確認し、実際に機能するサンプルをテストして、それらの違いを確認できるようにします。

次の例では、次のような構造の単純なXMLファイルを使用します。

<tutorials>
    <tutorial tutId="01" type="java">
        <title>Guava</title>
        <description>Introduction to Guava</description>
        <date>04/04/2016</date>
        <author>GuavaAuthor</author>
    </tutorial>
    ...
</tutorials>

4. DOM4J

まず、 DOM4J で何ができるかを見ていきます。この例では、この依存関係の最後のバージョンを追加する必要があります。

これは、 XML ファイルで動作する最も人気のあるライブラリの1つです。これにより、双方向の読み取り、新しいドキュメントの作成、および既存のドキュメントの更新が可能になります。

DOM4J は、 DOM SAX XPath 、およびXLSTと連携できます。 SAX は、JAXPを介してサポートされます。

たとえば、ここで、特定のIDでフィルタリングする要素を選択する方法を見てみましょう。

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

SAXReader クラスは、SAX解析イベントからDOM4Jツリーを作成する役割を果たします。 org.dom4j.Document を取得したら、必要なメソッドを呼び出して、XPath式をString。として渡す必要があります。

既存のドキュメントをロードし、そのコンテンツに変更を加えてから、元のファイルを更新できます。

for (Node node : nodes) {
    Element element = (Element)node;
    Iterator<Element> 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 を呼び出し、ノードの名前を渡すことでリスト内のすべてのタイトルのノードを取得するのがいかに簡単であるかに注目してください。

コンテンツを変更したら、DOM4Jツリーを取得してXMLとしてストリームにフォーマットするXMLWriterを使用します。

新しいドキュメントを最初から作成するのは、以下のように簡単です。

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 は、 createDocument など、 DOM4J で使用するメソッドのコレクションを提供し、空のドキュメントを作成して作業を開始します。

DOM4J が提供するメソッドを使用して、必要な数の属性または要素を作成できます。ドキュメントが完成したら、前の更新の場合と同じようにファイルに書き込みます。

5. JDOM

JDOM、を使用するには、この依存関係をpomに追加する必要があります。

JDOMのの作業スタイルは、 DOM4Jのと非常に似ているため、いくつかの例を見ていきます。

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

上記の例では、 DOM4J:で実行できるように、非常に簡単な方法でルート要素からすべての要素を取得しています。

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

繰り返しになりますが、上記のコードでは、 SAXBuilder が、指定されたファイルからDocumentインスタンスを作成しています。 JDOM2。によって提供されるXPathFactoryXPath式を渡すことにより、tutId属性によって要素を取得しています。

6. StAX

次に、 StaxAPIを使用してルート要素からすべての要素を取得する方法を見ていきます。 StaxはJava6以降JDKに含まれているため、依存関係を追加する必要はありません。

まず、Tutorialクラスを作成する必要があります。

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<Tutorial> 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

JAXBJDKに含まれており、Xercesも含まれているため、これに追加の依存関係は必要ありません。

JAXB を使用して、 XML ファイルから情報をロード、作成、および操作するのは非常に簡単です。

XML をバインドするために、正しいjavaエンティティを作成する必要があります。それだけです。

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

上記の例では、 XML ファイルをオブジェクトにロードし、そこからすべてを通常のJava構造として処理できます。

新しいドキュメントを作成するには、それを読むのと同じくらい簡単ですが、以下のコードで行うように、逆の方法で実行します。

まず、 Tutorial クラスを変更して、JAXBアノテーションをgettersおよび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> tutorial;

    // standard getters and setters with @XmlElement annotation
}

@XmlRootElement を使用して、ドキュメントのルートノードを表すオブジェクトを定義し、@XmlAttributeまたは@XmlElementを使用してその属性が表すかどうかを定義しますドキュメントのノードまたは要素の属性。

次に、次のようにフォローできます。

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);

ご覧のとおり、XMLファイルをJavaオブジェクトにバインドするのが、この種のファイルを処理する最も簡単な方法です。

8. XPath式のサポート

複雑なXPath式を作成するには、Jaxenを使用できます。 これは、 DOM XOM DOM4J JDOMなどのさまざまなオブジェクトモデルに適応できるオープンソースのXPathライブラリです。

XPath式を作成し、サポートされている多くのドキュメントに対してコンパイルできます。

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

これを機能させるには、この依存関係をプロジェクトに追加する必要があります。

9. 結論

ご覧のとおり、 XML を使用するための多くのオプションがありますが、アプリケーションの要件に応じて、それらのいずれかを使用することも、効率と単純さのどちらかを選択する必要がある場合もあります。

この記事の完全な動作サンプルは、gitリポジトリこちらにあります。