如何在实现项目阅读器时阅读非重复元素?

时间:2013-06-17 20:55:32

标签: spring-batch

我有一个场景,我必须读取这样的xml:

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

我必须阅读电影标签,这是一个复杂的对象(标签),并将细节插入电影表。我已将fragmentRootElementName设置为Movie,并且能够完全读取Movie标签。但是,我无法读取语言属性,这不是重复标记。

我应该如何获取不重复的标签详细信息?我应该自己解析XML来阅读吗?或者我应该再写一个fragmentRootElementName来读取语言属性吗?

项目阅读器的配置如下:

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

1 个答案:

答案 0 :(得分:2)

好的,简单的方法是定义你的fragmentRootElementName = MovieList,但我想如果你的MovieList可以包含数百万部电影,这不是一个好主意!

我有一个类似的问题,我需要知道我的fragmentRootElementName的父标签。

因此我们创建了一个CustomStaxEventItemReader,它扩展了原始的StaxEventItemReader。

我们添加了您可以在配置中设置的属性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解组它并返回相关的对象。

现在,我们只添加一些代码来查找给定的父元素。我使用了名为ParentTags的Enum,因为我的XML更复杂,但您只能比较配置中定义的新parentElement的名称。

因此,如果实际元素isEquals到您的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;
}

我希望这很清楚!

祝你好运和问候