如何在java中解组这种类型的xml

时间:2016-06-11 06:48:16

标签: java xml rest jaxb dtd

我是Rest API的新手。我有一个xml输出,我需要解组。下面是xml输出:

<dsml>
    <entries>
        <entry dn="uid=7686,c=in,ou=pages,o=example.com">
            <att name="uid">
                <value>7568766</value>
            </att>
            <att name="email">
                <value>new@gmail.com</value>
            </att>
            <att name="callname">
                <value>John</value>
            </att>
        </entry>
        <entry dn="uid=7689,c=in,ou=pages,o=example.com">
            <att name="uid">
                <value>7678766</value>
            </att>
            <att name="callname">
                <value>Mike</value>
            </att>
        </entry>
        <entry dn="uid=7690,c=in,ou=pages,o=example.com">
            <att name="uid">
                <value>75858766</value>
            </att>
            <att name="email">
                <value>old@gmail.com</value>
            </att>
            <att name="callname">
                <value>rahul</value>
            </att>
        </entry>
    </entries>
</dsml>

实际的xml输出共有37个条目。以下是模型类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "user")
public class User implements Serializable{
    private static final long serialVersionUID = 1L;

    @XmlElement(name = "uid")
    private int uid;

    @XmlElement(name = "callname")
    private String callname;

    @XmlElement(name = "email")
    private String email;

    public int getId() {
        return uid;
    }
    public void setId(int uid) {
        this.uid = uid;
    }
    public String getFirstName() {
        return callname;
    }
    public void setFirstName(String callname) {
        this.callname = callname;
    }
    public String getmail() {
        return email;
    }
    public void setmail(String email) {
        this.email = email;
    }
}

以下是Rest Api类代码:

public class UsingRestAPI {
    public static void main(String[] args) 
    {
        try
        {
            URL url = new URL("www.example.com");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "application/xml");

            if (conn.getResponseCode() != 200) 
            {
                throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
            }

            BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
            String apioutput="",temp="";
            while ((apioutput = br.readLine()) != null) {
                temp += apioutput;
                System.out.println(apioutput);
            }


            JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            User user = (User) jaxbUnmarshaller.unmarshal(new StringReader(temp));

            System.out.println(user.getId());
            System.out.println(user.getFirstName());
            System.out.println(user.getmail());

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

执行此代码时,我收到错误

javax.xml.bind.UnmarshalException   - 链接异常: [org.xml.sax.SAXParseException; lineNumber:1; columnNumber:110;外部DTD:无法读取外部DTD“dsml.dtd”,因为由于accessExternalDTD属性设置的限制而不允许“http”访问。]

我已尝试将属性ACCESS_EXTERNAL_DTD更改为true,但它又出现了另一个错误:

javax.xml.bind.PropertyException: name: http://javax.xml.XMLConstants/property/accessExternalDTD value: true
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.setProperty(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.setProperty(Unknown Source)
    at UsingRestAPI.main(UsingRestAPI.java:60)

3 个答案:

答案 0 :(得分:0)

(编辑回答:编辑了UserClass和DsmlFactory getEntities()方法)

我认为这是因为你的Xml结构和你的类结构不同。我永远不会使用具有相同名称但不同值类型的元素(例如您的attvalue元素)。为什么?对于Marshaller来说这不是问题,对于Unmarshaller来说这是一个问题。因为,据我所知,它无法根据父项name属性定义子元素值的类型。即使您定义了泛型类型的静态内部类(例如interface Attribute<V>static class Uid<Integer>static class Email<String>等等,您的工作也会更复杂。

但是如果你写了@XmlElement(name="att") Set<Attribute> attributes,其中属性计数对于Marshaller和Unmarshaller来说并不重要,那么它就是其他东西。

但是为了简单起见,我真的会推荐结构<email>{value}</email><uid>{value}</uid>等。

我已经制作了一个简单的Xml Marshaller / Unmarshaller进行测试(没有REST),这有效:

我的Dslm Xml根类:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Dsml {

    @XmlElement
    private Entities entities;

    public Dsml() {}
    public Dsml(Entities entities) {
        this.entities = entities;
    }

    public Entities getEntities() {
        return entities;
    }

    public void print() {
        entities.print();
    }
}

我的Entities课程:

@XmlAccessorType(XmlAccessType.FIELD)
public class Entities {
    @XmlElement(name = "entity")
    private Set<User> users = new LinkedHashSet<>();

    public Entities() {}

    public Entities(Set<User> users) {
        this.users = users;
    }

    public Set<User> getUsers() {
        return Collections.unmodifiableSet(users);
    }

    public void print() {
        if (users != null && !users.isEmpty()) {
            users.stream().forEach(User::print);
        } else {
            System.out.println("No entities found");
        }
    }
}

我的User课程:

@XmlAccessorType(XmlAccessType.FIELD)
public class User {

    @XmlAttribute
    private String dn;

    @XmlElement
    private int uid;

    @XmlElement
    private String email;

    @XmlElement
    private String callname;


    public User() {}

    public User(int uid, String dn, String email, String callname) {
        setUid(uid);
        setEmail(email);
        setCallname(callname);
        setDn(dn);
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCallname() {
        return callname;
    }

    public void setCallname(String callname) {
        this.callname = callname;
    }

    public String getDn() {
        return dn;
    }

    public void setDn(String dn) {
        this.dn = dn;
    }

    public void print() {
        System.out.println("Dn: " + dn);
        System.out.println("Uid: " + uid);
        System.out.println("Email: " + email);
        System.out.println("Callname: " + callname);
    }
}

我的DsmlFactory Marshaller / Unmarshaller测试类(确保您拥有D:\分区,并且您拥有Read | ReadWrite权限,或者在方法saveXml()和{{}中键入任何其他路径1}}:

readAndPrint()

我的public final class DsmlFactory { private DsmlFactory() {} public static Entities getEntities() { Set<User> users = new LinkedHashSet<>(); users.add(new User(1000, "dn1", "email1", "callname1")); users.add(new User(2000, "dn2", "email2", "callname2")); users.add(new User(3000, "dn3", "email3", "callname3")); users.add(new User(4000, "dn4", "email4", "callname4")); users.add(new User(5000, "dn5", "email5", "callname5")); return new Entities(users); } public static void saveXmlTest() { try { File file = new File("D:/test.xml"); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } JAXBContext jaxbContext = JAXBContext.newInstance(Dsml.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Dsml dsml = new Dsml(getEntities()); jaxbMarshaller.marshal(dsml, file); jaxbMarshaller.marshal(dsml, System.out); } catch (JAXBException e) { e.printStackTrace(); } } public static void readAndPrintXml() { JAXBContext jaxbContext; try { jaxbContext = JAXBContext.newInstance(Dsml.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Dsml dsml = (Dsml) jaxbUnmarshaller.unmarshal( new File("D:/test.xml") ); dsml.print(); } catch (JAXBException e) { e.printStackTrace(); } } public static void testIt() { saveXmlTest(); readAndPrintXml(); } } TestDrive:

main

答案 1 :(得分:0)

为什么不将Xml保存在文件中,然后将其传递给unmarshal

新版本_:

User user = (User) jaxbUnmarshaller.unmarshal(new File("c:/temp/user.xml") );//File path

它不会给出任何错误。

访问 - :http://howtodoinjava.com/jaxb/jaxb-exmaple-marshalling-and-unmarshalling-list-or-set-of-objects/

答案 2 :(得分:0)

我建议您尝试以下方法:

步骤1:创建名为Attribute的类,如下所示:

Attribute.java

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

public class Attribute implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
public Attribute() {
 }
public Attribute(String name, String value) {
    this.name = name;
    this.value = value;
 }
@XmlAttribute
public String getName() {
    return name;
 }
public void setName(String name) {
    this.name = name;
 }
@XmlElement
public String getValue() {
    return value;
 }
public void setValue(String value) {
    this.value = value;
 }
}

第2步:请修改名为Student的班级,如下所示:

Student.java

import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private List<Attribute> attributes;
private String distinguishedName;
public Student() {
 }
public Student(String distinguishedName, List<Attribute> attributes) {
    this.distinguishedName = distinguishedName;
    this.attributes = attributes;
 }
@XmlAttribute(name = "dn")
public String getDistinguishedName() {
    return distinguishedName;
 }
public void setDistinguishedName(String distinguishedName) {
    this.distinguishedName = distinguishedName;
 }
@XmlElement(name = "att", type = Attribute.class)
public List<Attribute> getAttributes() {
    return attributes;
 }
public void setAttributes(List<Attribute> attributes) {
    this.attributes = attributes;
 }

}

步骤3:请创建一个名为DSML的类,如下所示:

DSML.java

import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "dsml")
public class DSML implements Serializable {
private static final long serialVersionUID = 1L;
private List<Student> entries;

@XmlElementWrapper(name = "entries")
@XmlElement(name = "entry", type = Student.class)
public List<Student> getEntries() {
    return entries;
 }
public void setEntries(List<Student> entries) {
    this.entries = entries;
 }
}

步骤4:现在是时候将XML转换为Java对象,如下所示:

UsingRestAPI.java

JAXBContext jaxbContext = JAXBContext.newInstance(DSML.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
DSML dsml = (DSML) jaxbUnmarshaller.unmarshal(new StringReader(temp));