こんにちは
2000年代初期からXML形式の人気が低下したにもかかわらず、XML形式はしっかりとその位置を占めました。 プロジェクトの60%でXML処理に出会い、Masterjavaでのインターンシップに専念しました。 その最も一般的な用途は、XHTML、SOAP、さまざまな構成(たとえば、Tomcat、SoapUI、IntelliJ IDEA、Spring XML構成)、データのインポート/エクスポートです。
JavaにはXMLを操作するためのAPIがいくつかあります。開発者は、特定の状況でどのAPIを選択するかを理解することが重要です。 この記事では、すべてのJava XML API、それらの目的と使用例を簡単にリストし、かなりまれですが、場合によっては唯一の真のStAXテクノロジーとの連携について説明します。 既にXML要素に精通していることを前提としています。
Java XML API:適切なものを選択する
- JAXP(XML処理用Java API)は、一連のAPI(SAX + DOM + DTD + XSLT検証)です。 XercesとXalanは、これらのAPIの標準実装です。 XSLTに加えて、すべてのAPIは非推奨です。SAXはStAXに、DOMはJAXBに、DTDはXSDに置き換えられました。
- DOMおよびJAXB -XMLを完全に読み取り、Javaオブジェクトでアプリケーションの既製表現を取得するためのAPI。 DOMの場合、これらはorg.w3c.dom.Nodeインターフェース (属性、要素、テキスト、..)の実装のコレクションです。 JAXBのマッピングは、ORMがデータベーステーブルのJavaオブジェクトへのマッピングを設定する方法と同様に設定されます。 すなわち XMLは既製の使いやすいJava Beanを作成します。 JAXBは、すべてのXMLを読み取り(JVMメモリに収まる必要がある)、必要なアクションを実行する必要があるときに、XMLを操作するための最も便利で頻繁に使用されるAPIです。
- DTD (非推奨)およびXSDは、XML構造の検証(要素の順序、要素の必須またはオプションの性質、要素上の属性の存在)を指定するスキーマです。 構造検証スキームをXMLに添付すると、XMLで動作するツール(たとえば、IntelliJ IDEA)がオートコンプリートを実行し、スキーマエラーを表示できます。 アプリケーションからXMLドキュメントを検証することもできます。 XSD形式はより近代的で、それ自体がXMLドキュメントです。
- XPathはXMLクエリ言語です。 XMLから特定の要素を抽出するか、その数を計算する必要があるコードについては、データベースに対するSQLクエリと大まかに比較できます。 たとえば、 ESBでのアプリケーションを見ました。システム間のデータはXML形式で送信され、各システムはXPathを介してXMLから必要なデータを「バイト」します。 ほとんどの場合、XMLの変換にはXPathが使用されます。
- XSL、XSLT -XMLを他の形式に変換します。 たとえば、アプリケーションの1つは、 サーバーからブラウザにXML応答を送信し、XSLからHTMLへの変換を指定することです。 最新のブラウザはすべて、XSLT変換をサポートしています。 クライアント側では、指定されたXSLに従ってXMLを必要な形式に個別に変換します。
- SAXおよびStAX -XMLソースからの順次読み取りドキュメントは、断片(イベント)で順次読み取られます。 APIは、SAXがプッシュモデルに基づいており、Staxがプルモデルに基づいているという点で異なります。 JavaScriptで複数の連続したAJAXリクエストを一度行った場合、 コールバックhellに遭遇しました。 コードの実行は非同期で行われ、コードは順番に書き込まれるのではなく、戻り関数のステップごとに書き込まれます。 SAXを使用すると、同様のことが起こります。XMLの特定のイベント(タグの開始、タグの終了、タグ内のテキスト、コメント)を処理する関数を定義し、これらのハンドラー内に新しいハンドラーを定義する必要があります。 StAXを使用する方がはるかに便利です。 ドキュメントからイベントを順番に読み取り、分析して適切なイベントを処理します。 これらのAPIは、非常に大きなドキュメントに使用されます。オブジェクトのリストは、ドキュメントに表示されるとき、またはドキュメント全体に関心がないときに一度に1つずつ読み取られ、ドキュメント全体の特定の部分とモデルは必要ありません。
APIの機能の比較ラベルで、 SAX / StAXの
Easy of Use
、作成者がStAXの操作方法を知らないことを示しており、記事の残りの部分では「適切に準備する」方法について説明します。
StAX:私たちは喜びをもって仕事をします
まず、2つのAPIを使用してStAXを操作できることに注意してください。プリミティブを返す低レベルのXMLStreamReaderと、オブジェクトを返し、より多くのメモリを消費する高レベルのXMLEventReaderです。 次に、XMLStreamReaderを使用します。 その上にラッパーを使用すると、XMLでの作業が簡単で便利になります小さな例を見てみましょう:都市とユーザーを含む単純なXMLがあります。
<Payload> <Cities> <City id="spb">-</City> <City id="mow"></City> ... </Cities> ... <Users> <User city="mow"> <email>gmail@gmail.com</email> <fullName>Gmail User</fullName> </User> <User city="spb"> <email>admin@javaops.ru</email> <fullName>Admin</fullName> </User> ... </Users> ... </Payload>
実際には、このXMLには数百の都市と数十万/ 100万のユーザーを含めることができます。 必要なのは、都市のリストを印刷することだけです。 この場合、StAX APIが唯一の正しい選択です。 補助クラスStaxStreamProcessor
をプロジェクトに追加します。
public class StaxStreamProcessor implements AutoCloseable { private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); private final XMLStreamReader reader; public StaxStreamProcessor(InputStream is) throws XMLStreamException { reader = FACTORY.createXMLStreamReader(is); } public XMLStreamReader getReader() { return reader; } @Override public void close() { if (reader != null) { try { reader.close(); } catch (XMLStreamException e) { // empty } } } }
次に、XMLを順番に調べ、関心のあるすべてのイベントを読み取り、必要な情報を表示します。 try (StaxStreamProcessor processor = new StaxStreamProcessor(Files.newInputStream(Paths.get("payload.xml")))) { XMLStreamReader reader = processor.getReader(); while (reader.hasNext()) { // while not end of XML int event = reader.next(); // read next event if (event == XMLEvent.START_ELEMENT && "City".equals(reader.getLocalName())) { System.out.println(reader.getElementText()); } } }
XMLで目的のイベントを検索するために頻繁に繰り返されるコードをプログラム内で絶えず複製しないように、 StaxStreamProcessor
追加できます。
public boolean doUntil(int stopEvent, String value) throws XMLStreamException { while (reader.hasNext()) { int event = reader.next(); if (event == stopEvent && value.equals(reader.getLocalName())) { return true; } } return false; }
ユーティリティクラスの使用は簡単ではありませんが、非常に簡単です。 while (processor.doUntil(XMLEvent.START_ELEMENT, "City")){ System.out.println(reader.getElementText()); }
このコードの欠点は、プログラムを完了する代わりに、必要のない数十万のユーザーを処理するためにリソースを費やすことはまったく役に立たないことです。 XMLのスキャンを停止するには、条件を追加する必要があります。 これは通常、親要素(この場合はCities
)のタグの終わりです。 親タグの末尾または指定された要素のいずれかにXMLをスキャンする別のユーティリティメソッドをStaxStreamProcessorに追加します。
public boolean startElement(String element, String parent) throws XMLStreamException { while (reader.hasNext()) { int event = reader.next(); if (parent != null && event == XMLEvent.END_ELEMENT && parent.equals(reader.getLocalName())) { return false; } if (event == XMLEvent.START_ELEMENT && element.equals(reader.getLocalName())) { return true; } } return false; }
属性とテキストを読み取るためのメソッドを追加します。 public String getAttribute(String name) throws XMLStreamException { return reader.getAttributeValue(null, name); } public String getText() throws XMLStreamException { return reader.getElementText(); }
呼び出しコードは非常にシンプルなままであり、 Cities
タグの終了後すぐにXMLの処理を停止します。
while (processor.startElement("City", "Cities")) { System.out.println(processor.getAttribute("id") +":" + processor.getText()); }
StAX APIでは、イベントの読み取りに正確さが必要です。 出力で属性とテキストの読み取りを省略したが、コードが機能しなくなった場合:XMLから都市名を読み取った後、属性は取り残され、アクセスできなくなります。 また、XMLの現在の状況に応じて、XMLから読み取るための一部のAPIメソッドが使用できる場合と使用できない場合があることもStaxStreamProcessor
必要があります。 このアプローチにより、StAXでの作業が簡単で便利に思えることを願っています。
ご清聴ありがとうございました。コーディングをお楽しみください!