さらに、さまざまな「深さ」にあるいくつかのタグのみを引き出す必要がありました。 XSLT「額の中」は、メモリ不足のため壊れました。 ストリームパーサーについて考えて覚えておく必要がありました。
いくつかのXML処理モデルがあります。 最も有名なのはDOMとSAXです。
DOMはXMLドキュメント全体をロードし、その内部表現を構築し、ドキュメント全体をナビゲートする機能を提供します。 一方、SAXは入力ドキュメントを読み取り、要素が認識されると、処理のためにハンドラーを呼び出します。
私の場合、DOMはメモリ消費のためにドロップしました。 SAX APIはハンドラー上に構築されているため、コードが読みにくくなります。 StAXは(SAXのような)ストリームパーサーですが、APIはプルの原則に基づいて構築されています。 つまり、認識された要素はオンデマンドでストリームから「削除」されます。
処理されるデータ構造は非常に複雑で多様であり、処理は非常に重要なため、JAXBを使用して内部表現に変換することが決定されました。
プロジェクトデータはNDAによって閉じられているため、この記事では使用されません。
そして、次のものがあります
XML文書
<data> <dtype_one> <p1>p1_data_1</p1> <p2>p1_data_1</p2> <p3>p1_data_1</p3> <p4>p1_data_1</p4> <p5>p1_data_1</p5> </dtype_one> <dtype_two> <p1>p1_data_2</p1> <p2>p1_data_2</p2> <p3>p1_data_2</p3> <p4>p1_data_2</p4> <p5>p1_data_2</p5> </dtype_two> <WS> <dtype_three> <p1>p1_data_3</p1> <p2>p1_data_3</p2> <p3>p1_data_3</p3> <p4>p1_data_3</p4> <p5>p1_data_3</p5> </dtype_three> </WS> </data>
それから、タグdtype_one、dtype_two、dtype_threeを選択して処理する必要があります。 ドキュメント内でタグが繰り返されています。 取る
文書概要
<?xml version="1.0" encoding="UTF-8"?> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="data" type="dataType"/> <xs:element name="dtype_one" type="dtype_oneType"/> <xs:element name="dtype_two" type="dtype_twoType"/> <xs:element name="dtype_three" type="dtype_threeType"/> <xs:complexType name="dtype_oneType"> <xs:sequence> <xs:element type="xs:string" name="p1"/> <xs:element type="xs:string" name="p2"/> <xs:element type="xs:string" name="p3"/> <xs:element type="xs:string" name="p4"/> <xs:element type="xs:string" name="p5"/> </xs:sequence> </xs:complexType> <xs:complexType name="dataType"> <xs:sequence> <xs:element type="dtype_oneType" name="dtype_one"/> <xs:element type="dtype_twoType" name="dtype_two"/> <xs:element type="WSType" name="WS"/> </xs:sequence> </xs:complexType> <xs:complexType name="WSType"> <xs:sequence> <xs:element type="dtype_threeType" name="dtype_three"/> </xs:sequence> </xs:complexType> <xs:complexType name="dtype_twoType"> <xs:sequence> <xs:element type="xs:string" name="p1"/> <xs:element type="xs:string" name="p2"/> <xs:element type="xs:string" name="p3"/> <xs:element type="xs:string" name="p4"/> <xs:element type="xs:string" name="p5"/> </xs:sequence> </xs:complexType> <xs:complexType name="dtype_threeType"> <xs:sequence> <xs:element type="xs:string" name="p1"/> <xs:element type="xs:string" name="p2"/> <xs:element type="xs:string" name="p3"/> <xs:element type="xs:string" name="p4"/> <xs:element type="xs:string" name="p5"/> </xs:sequence> </xs:complexType> </xs:schema>
そして、必要なタグの「要素」の要素があることを確認してください:
<xs:element name="dtype_one" type="dtype_oneType"/> <xs:element name="dtype_two" type="dtype_twoType"/> <xs:element name="dtype_three" type="dtype_threeType"/>
スキーマがない場合、IDEAはxmlファイルから完全にスキーマを生成できます。
これは、 XJCが@XmlRootElementアノテーションを生成するためのものです。 プロジェクトはmavenになります。maven-jaxb2-pluginを使用してXJCを呼び出します。 スキーマファイルのすべての「要素」に対して@XmlRootElementを生成するには、次の行をbindings.xjbファイルに追加する必要があります。
<jaxb:bindings> <jaxb:globalBindings > <xjc:simple/> </jaxb:globalBindings> </jaxb:bindings>
そして、 pom.xmlのプラグイン構成maven-jaxb2-pluginで接続します
<bindingDirectory>${project.basedir}/xjb</bindingDirectory>
さて、実際にはコードに対して、 TagEngineクラスはタグハンドラーのリストを保存し、 それを解析します :
public void process(InputStream inputStream) throws FileNotFoundException, XMLStreamException, TransformerException { // XMLStreamReader, XMLInputFactory factory = XMLInputFactory.newFactory(); XMLStreamReader streamReader = factory.createXMLStreamReader(inputStream); // Stack<String> tagStack = new Stack<String>(); // while (streamReader.hasNext()) { // int eventType = streamReader.next(); // if(eventType == XMLStreamConstants.START_ELEMENT) { // tagStack.push(streamReader.getName().toString()); // TagProcessor t = processorMap.get(tagStack); if(t != null) { // , t.process(streamReader); tagStack.pop(); } } else if(eventType == XMLStreamConstants.END_ELEMENT) { tagStack.pop(); } } }
JAXBProcessorクラスは、選択された要素を非整列化します。 XSLTProcessorクラスは、XSLT変換を呼び出します。 これは、有用な作業を行うクラスのようです。
public class DataOne extends JAXBProcessor<DtypeOne> { private static final String TAG_NAME = "data/dtype_one"; // public DataOne() throws JAXBException, SAXException { super(DtypeOne.class, TAG_NAME); } // public DataOne(String schemaFileName) throws JAXBException, SAXException { super(DtypeOne.class, TAG_NAME, schemaFileName); } // XML @Override public void doWork(DtypeOne element) { // System.out.println(element.getP1()); } }
XSLT DataThreeXSLTアプリケーションの例。
起動例(277メガバイトのファイルの処理がエミュレートされます):
スキーマ検証なしのJAXBアンマーシャル ランタイム:8034ms、277000015バイト処理 使用メモリ:80MB スキーマ検証によるJAXBアンマーシャル ランタイム:66180ms、277000015バイト処理 使用メモリ:56MB XSLT処理 ランタイム:10604ms、277000015バイト処理 使用メモリ:231MB
すべてはメモリで問題ありません。もちろん、検証によって処理が大幅に遅くなります。
PS。 テストにはMockitoを使用しました (以前はjmockを使用しました)。 私はスパイの可能性が好きでした-ライブ(モックではない)オブジェクトを操作するときに呼び出しとそのパラメーターをインターセプトします
PPS GitHubプロジェクトコード。