【问题标题】:How to unmarshal this type of xml in java如何在java中解组这种类型的xml
【发布时间】:2016-10-12 03:57:26
【问题描述】:

我是 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;行号:1;列号: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)

【问题讨论】:

    标签: java xml rest jaxb dtd


    【解决方案1】:

    为什么不将 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】:

      (已编辑答案:已编辑 UserClass 和 DsmlFactory getEntities() 方法)

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

      但是如果你写了@XmlElement(name="att") Set&lt;Attribute&gt; attributes,其中属性计数对于 Marshaller 和 Unmarshaller 并不重要,那就是另外一回事了。

      不过为了简单起见,我真的推荐&lt;email&gt;{value}&lt;/email&gt;&lt;uid&gt;{value}&lt;/uid&gt;等结构。

      我已经制作了一个简单的 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()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();
          }
      }
      

      还有我的mainTestDrive:

      public class Main {
          public static void main(String[] args) {
              DsmlFactory.testIt();
          }
      }
      

      【讨论】:

        【解决方案3】:

        我建议您尝试以下方法:

        第一步:创建一个名为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 的类,如下所示:

        学生.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));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多