0

次のような xml を読み取らなければならないシナリオがあります。

<MovieList language="English">
  <Movie>..<Movie>
  <Movie>..<Movie>
</MovieList>

複雑なオブジェクト (タグ) であるムービー タグを読み取り、詳細をムービー テーブルに挿入する必要があります。fragmentRootElementName を Movie に設定し、Movie タグを完全に読み取ることができました。ただし、繰り返しタグではない言語属性を読み取ることができません。

非繰り返しタグの詳細を取得するにはどうすればよいですか? XML を自分で解析して読み取る必要がありますか? または、言語属性を読み取るためだけに、fragmentRootElementName をもう 1 つ記述する必要がありますか?

アイテム リーダーの構成は次のとおりです。

<bean id="movieReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
  <property name="unmarshaller" ref="marshaller" />
  <property name="fragmentRootElementName" value="Movie" />
  <property name="resource" value="file:#{jobParameters['inputFile']}" />
</bean>
4

1 に答える 1

2

わかりました、簡単な方法はfragmentRootElementName = MovieListを定義することですが、MovieListに何百万もの映画を含めることができる場合、これは良い考えではないと思います!!

fragmentRootElementName の親タグを知る必要があるという同様の問題がありました。

そこで、元の StaxEventItemReader を拡張する CustomStaxEventItemReader を作成しました。

設定で設定できるプロパティparentElementを追加しました。そして、メソッド moveCursorToNextFragment() と doRead() をオーバーライドして、この問題に対処できるようにします。

今、私が持っているコードはあなたが必要としているものを正確に実行していませんが、私はそれを修正し、動作しているように見えます!!!

protected boolean moveCursorToNextFragment(XMLEventReader reader) {
 try {
    while (true) {
        while (reader.peek() != null && !reader.peek().isStartElement()) {
            reader.nextEvent();
        }
        if (reader.peek() == null) {
            return false;
        }
        XMLEvent ev = reader.peek();
        QName startElementName = ((StartElement) ev).getName();

        // Take note of current parent element. Must be one of
        // ParentTags
        String tmp = startElementName.getLocalPart();
        for (ParentTags aTag : ParentTags.values()) {
            if (aTag.toString().equals(tmp)) {
                currentParent = tmp;
                Attribute attr = ((StartElement) ev)
                            .getAttributeByName(new QName("Language"));
                    if (null != attr) {
                        parentAttribute = attr.getValue();
                    }
                    break;
                }
            }

            if (startElementName.getLocalPart().equals(
                    fragmentRootElementName)) {
                if ((fragmentRootElementNameSpace == null && parentElement
                        .equals(currentParent))
                        || startElementName.getNamespaceURI().equals(
                                fragmentRootElementNameSpace)) {
                    return true;
                }
            }

            reader.nextEvent();

        }
    } catch (XMLStreamException e) {
        throw new DataAccessResourceFailureException(
                "Error while reading from event reader", e);
    }
}

基本的に、元の StaxEventReader のコードを見ると、xml ファイルのすべての要素を通過していることがわかります。= という名前の要素を rootElement に取得するたびに、true を返し、doRead はそれを非整列化し、関連付けられたオブジェクトを返します。

ここで、特定の親要素を見つけるためのコードを追加するだけです。私の XML はもう少し複雑だったので、ParentTags という Enum を使用しましたが、構成で定義された新しい parentElement の名前しか比較できませんでした。

したがって、実際の要素がparentElementと等しい場合、それをcurrentParentに割り当てて、属性を取得しようとするだけです。null でない場合は、parentAttribute プロパティに割り当てます。

その後、doRead() メソッドで、parentAttribute プロパティにアクセスして、ドメイン オブジェクトに設定できます。

    protected T doRead() throws Exception {

    if (noInput) {
        return null;
    }

    T item = null;

    if (moveCursorToNextFragment(fragmentReader)) {
        fragmentReader.markStartFragment();

        @SuppressWarnings("unchecked")
        T mappedFragment = (T) unmarshaller.unmarshal(StaxUtils
                .createStaxSource(fragmentReader));

        item = mappedFragment;
        logger.info("Item read : " + item);
        currentIndex = cIndex.getAndIncrement();

        T p = (T) item;
        if (p instanceof myDomainObj) {
            myDomainObj pp = (myDomainObj) p;
            logger.info(pp);
            logger.info("attribute parent = " + parentAttribute);
                            pp.setLanguage(parentAttribute);
        }
        fragmentReader.markFragmentProcessed();
    }

    return item;
}

これが十分に明確であることを願っています!

幸運を祈ります

于 2013-06-18T16:54:04.160 に答える