0

我有一个场景,我必须读取这样的 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>
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 会解组它并返回关联的对象。

现在,我们只添加一些代码来查找给定的父元素。我使用了一个名为 ParentTags 的枚举,因为我的 XML 有点复杂,但您只能比较配置中定义的新 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 回答