使用JAXB基于属性解析XML

3

我正在使用JAXB解析一些XML。

<countries>
    <Name language="en">Australia</Name>
    <Name language="se">Australien</Name>
</countries>

如果我在我的 Countries 类中使用

@XmlElement(name = "Name", required = true)
    protected List<Name> name;

一切都正常。

但我想仅获取语言属性为“en”的属性。

因此,在我的Countries类中,有

protected String name

不是一个集合。

有没有一种好的方法来通过一些注释解决这个问题?

1个回答

4

注意: 我是EclipseLink JAXB (MOXy)的主管和JAXB (JSR-222)专家组成员。

以下是处理此用例的两种方法。第一种代码有点多,但可以使用任何JAXB实现。第二种代码较少,但需要使用EclipseLink JAXB (MOXy)。

选项#1 - 任何JAXB (JSR-222)实现

演示

您可以使用过滤流读取器来过滤掉不需要的元素,并让您的JAXB实现对其进行解组。

package forum11586106;

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static final String LANGUAGE_CODE = "en";

    public static void main(String[] args) throws Exception {
        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/forum11586106/input.xml"));
        xsr = xif.createFilteredReader(xsr, new StreamFilter() {

            private boolean isReading = true;

            @Override
            public boolean accept(XMLStreamReader reader) {
                if(reader.isStartElement() && "Name".equals(reader.getLocalName())) {
                    isReading = LANGUAGE_CODE.equals(reader.getAttributeValue("", "language"));
                    return isReading;
                } else if(reader.isEndElement() && !isReading) {
                    isReading = true;
                    return false;
                }

                return true;
            }});

        JAXBContext jc = JAXBContext.newInstance(Countries.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Countries countries = (Countries) unmarshaller.unmarshal(xsr);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(countries, System.out);
    }

}

国家

package forum11586106;

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Countries {

    private String name;

    @XmlElement(name="Name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

input.xml

采用这种方法,输出中不包含语言属性:

<countries>
    <Name language="en">Australia</Name>
    <Name language="se">Australien</Name>
</countries>

输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<countries>
    <Name>Australia</Name>
</countries>

选项 #2 - ECLIPSELINK JAXB (MOXy)

我们将利用 MOXy 的 @XmlPath 扩展来映射到具有 language 属性值为 enName 元素(请参见 http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html)。

国家

package forum11586106;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
public class Countries {

    private String name;

    @XmlPath("Name[@language='en']/text()")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

jaxb.properties

如果要使用MOXy作为您的JAXB提供程序,您需要在与您的领域模型相同的包中包含一个名为 jaxb.properties 的文件,并包含以下条目(参见:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示

使用这种方法,元素过滤由@XmlPath映射处理,因此运行时部分变得更简单。请注意,只使用标准的JAXB运行时API。

package forum11586106;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Countries.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum11586106/input.xml");
        Countries countries = (Countries) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(countries, System.out);
    }

}

input.xml

<countries>
    <Name language="en">Australia</Name>
    <Name language="se">Australien</Name>
</countries>

输出

使用这种方法,language 属性将被包含在输出中:

<?xml version="1.0" encoding="UTF-8"?>
<countries>
   <Name language="en">Australia</Name>
</countries>

谢谢!第一个版本运行得很完美。我通常不用Eclipse,但是我尝试了一下,可是没法让MOXy版本工作。 - Patrik
@PatrikNilsson - 你需要确保使用的是EclipseLink 2.3或更高版本(当前版本为EclipseLink 2.4)。你可以从以下链接下载独立版本的EclipseLink:http://www.eclipse.org/eclipselink/downloads/ - bdoughan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接