如何通过SimpleXML解析XML

时间:2022-10-20 18:45:39

I am trying to parse the below XML using SimpleXML parsing.
I have tried in different ways to parse the Attributes of the Element but unable to get success in parsing the below XML.
It generates an error that is list at the bottom.

我正在尝试使用SimpleXML解析来解析下面的XML。我尝试了不同的方法来解析元素的属性,但是在解析下面的XML方面没有取得成功。它会生成一个位于底部的错误列表。

<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
  <order>
    <id>1</id>
    <id_address_delivery xlink:href="http://abc.com/add/1">1</id_address_delivery>
    <id_address_invoice xlink:href="http://abc.com/add/2">2</id_address_invoice>
  </order>
</prestashop>

Order.java

Order.java

@Root(name="order")
@Namespace(reference="http://www.w3.org/1999/xlink",prefix="xlink")
public class Order {

    @Element(name="id",required=true)
    private int order_id;

    @Element(name="id_address_delivery",required=false)
    private int id_address_delivery;
    @Attribute( name="href", required=false)
    private String id_address_delivery_href;


    @Element(name="id_address_invoice",required=false)
    private int id_address_invoice;
    @Attribute(name="href", required=false)
    private String id_address_invoice_href;
}

OrderObject.java

OrderObject.java

public class OrderObject
{
    @ElementList(required=true, inline=true)
    private List<Order> list = new ArrayList<Order>();

    public List<Order>getList()
    {
        return this.list;
    }
}

Exception that I get is :

我得到的例外是:

WARN/System.err(988): org.simpleframework.xml.core.PersistenceException: 
Duplicate annotation of name 'href' on field 'id_address_delivery_href' 
private java.lang.String com.prestashop.orders.Order.id_address_delivery_href
at org.simpleframework.xml.core.StructureBuilder.process(StructureBuilder.java:250)
at org.simpleframework.xml.core.StructureBuilder.process(StructureBuilder.java:173)
at org.simpleframework.xml.core.ObjectScanner.field(ObjectScanner.java:438)
at org.simpleframework.xml.core.ObjectScanner.scan(ObjectScanner.java:371)
at org.simpleframework.xml.core.ObjectScanner.<init>(ObjectScanner.java:82)
.
.

1 个解决方案

#1


8  

The reason for this exception are your both @Attribute annotations. They aren't set to the next element but to the entire Order object. Your annotations would set href twice, but with different values.

出现这种异常的原因是您的两个@Attribute。它们不是设置为下一个元素,而是设置为整个Order对象。注释将设置href两次,但值不同。

Please see JavaDoc of @Attribute:

请参见@Attribute的JavaDoc:

The Attribute annotation represents a serializable XML attribute within an XML element. [...]

属性注释表示XML元素中可序列化的XML属性。[…]

But there's a nice and simple solution: Instead of combining element and attribute, make a class which does this.

但是有一个很好的简单的解决方案:与其将元素和属性结合起来,不如创建一个这样做的类。

OrderObject class:

@Root(name = "prestashop")
@Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
public class OrderObject
{
    @ElementList(required = true, inline = true)
    private List<Order> list;


    public OrderObject()
    {
        this.list = new ArrayList<>();
    }


    public List<Order> getList()
    {
        return list;
    }


    // ...

    @Override
    public String toString()
    {
        return "OrderObject{" + "list=" + list + '}';
    }

}

Note: The toString() methods in these classes are only implemented to check the result!

注意:这些类中的toString()方法仅用于检查结果!

Order class:

@Root(name = "order")
public class Order
{
    @Element(name = "id")
    private int id;
    @Element(name = "id_address_delivery")
    private AdressDelivery delivery;
    @Element(name = "id_address_invoice")
    private AdressInvoice invoice;


    public Order(int id, AdressDelivery delivery, AdressInvoice invoice)
    {
        this.id = id;
        this.delivery = delivery;
        this.invoice = invoice;
    }

    private Order() {  }


    // Getter / Setter etc.


    @Override
    public String toString()
    {
        return "Order{" + "id=" + id + ", delivery=" + delivery + ", invoice=" + invoice + '}';
    }


    @Root()
    public static class AdressDelivery
    {
        @Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
        @Attribute(name = "href", required = false)
        private String link;
        @Text()
        private int value;


        public AdressDelivery(String link, int value)
        {
            this.link = link;
            this.value = value;
        }

        AdressDelivery() { }



        // Getter / Setter etc.

        @Override
        public String toString()
        {
            return "AdressDelivery{" + "link=" + link + ", value=" + value + '}';
        }
    }

    @Root()
    public static class AdressInvoice
    {
        @Attribute(name = "href", required = false)
        @Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
        private String link;
        @Text()
        private int value;


        public AdressInvoice(String link, int value)
        {
            this.link = link;
            this.value = value;
        }

        AdressInvoice() { }


        // Getter / Setter etc.

        @Override
        public String toString()
        {
            return "AdressInvoice{" + "link=" + link + ", value=" + value + '}';
        }
    }

}

You can see the AdressDelivery and AdressInvoice classes which combine attribute and element. You do not have to implement them as inner classes; feel free to write them as "normal" one. You also do not have to make them public, even private is possible (eg. construct them within the Order's constructor.

您可以看到AdressDelivery和AdressInvoice类,它们结合了属性和元素。您不必将它们实现为内部类;把它们写成“正常的”。你也不必把它们公布于众,即使是私下的也可以。在Order的构造函数中构造它们。

But please note the empty constructors without arguments in Order class (and it's inner classes). They are required. But you can make all of them private - no need to expose them. It's only important that you have a constructor without arguments.

但是请注意在Order类中没有参数的空构造函数(它是内部类)。他们是必需的。但是你可以把它们都变成私有的——不需要公开它们。只有有一个没有参数的构造函数才是重要的。

How to use (example):

File f = new File("whatever.xml");

Serializer ser = new Persister();
OrderObject orderObject = ser.read(OrderObject.class, f);

System.out.println(orderObject);

This code parses the Xml from file and prints the deserialized object.

这段代码从文件中解析Xml并打印反序列化对象。

Input Xml (as in your question):

输入Xml(如您的问题):

<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
  <order>
    <id>1</id>
    <id_address_delivery xlink:href="http://abc.com/add/1">1</id_address_delivery>
    <id_address_invoice xlink:href="http://abc.com/add/2">2</id_address_invoice>
  </order>
</prestashop>

Result (from println()):

结果从println()():

OrderObject{list=[Order{id=1, delivery=AdressDelivery{link=http://abc.com/add/1, value=1}, invoice=AdressInvoice{link=http://abc.com/add/2, value=2}}]}

Not clearly represented, but enough to see the result :-)

没有明确的表示,但足以看到结果:-)

#1


8  

The reason for this exception are your both @Attribute annotations. They aren't set to the next element but to the entire Order object. Your annotations would set href twice, but with different values.

出现这种异常的原因是您的两个@Attribute。它们不是设置为下一个元素,而是设置为整个Order对象。注释将设置href两次,但值不同。

Please see JavaDoc of @Attribute:

请参见@Attribute的JavaDoc:

The Attribute annotation represents a serializable XML attribute within an XML element. [...]

属性注释表示XML元素中可序列化的XML属性。[…]

But there's a nice and simple solution: Instead of combining element and attribute, make a class which does this.

但是有一个很好的简单的解决方案:与其将元素和属性结合起来,不如创建一个这样做的类。

OrderObject class:

@Root(name = "prestashop")
@Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
public class OrderObject
{
    @ElementList(required = true, inline = true)
    private List<Order> list;


    public OrderObject()
    {
        this.list = new ArrayList<>();
    }


    public List<Order> getList()
    {
        return list;
    }


    // ...

    @Override
    public String toString()
    {
        return "OrderObject{" + "list=" + list + '}';
    }

}

Note: The toString() methods in these classes are only implemented to check the result!

注意:这些类中的toString()方法仅用于检查结果!

Order class:

@Root(name = "order")
public class Order
{
    @Element(name = "id")
    private int id;
    @Element(name = "id_address_delivery")
    private AdressDelivery delivery;
    @Element(name = "id_address_invoice")
    private AdressInvoice invoice;


    public Order(int id, AdressDelivery delivery, AdressInvoice invoice)
    {
        this.id = id;
        this.delivery = delivery;
        this.invoice = invoice;
    }

    private Order() {  }


    // Getter / Setter etc.


    @Override
    public String toString()
    {
        return "Order{" + "id=" + id + ", delivery=" + delivery + ", invoice=" + invoice + '}';
    }


    @Root()
    public static class AdressDelivery
    {
        @Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
        @Attribute(name = "href", required = false)
        private String link;
        @Text()
        private int value;


        public AdressDelivery(String link, int value)
        {
            this.link = link;
            this.value = value;
        }

        AdressDelivery() { }



        // Getter / Setter etc.

        @Override
        public String toString()
        {
            return "AdressDelivery{" + "link=" + link + ", value=" + value + '}';
        }
    }

    @Root()
    public static class AdressInvoice
    {
        @Attribute(name = "href", required = false)
        @Namespace(reference = "http://www.w3.org/1999/xlink", prefix = "xlink")
        private String link;
        @Text()
        private int value;


        public AdressInvoice(String link, int value)
        {
            this.link = link;
            this.value = value;
        }

        AdressInvoice() { }


        // Getter / Setter etc.

        @Override
        public String toString()
        {
            return "AdressInvoice{" + "link=" + link + ", value=" + value + '}';
        }
    }

}

You can see the AdressDelivery and AdressInvoice classes which combine attribute and element. You do not have to implement them as inner classes; feel free to write them as "normal" one. You also do not have to make them public, even private is possible (eg. construct them within the Order's constructor.

您可以看到AdressDelivery和AdressInvoice类,它们结合了属性和元素。您不必将它们实现为内部类;把它们写成“正常的”。你也不必把它们公布于众,即使是私下的也可以。在Order的构造函数中构造它们。

But please note the empty constructors without arguments in Order class (and it's inner classes). They are required. But you can make all of them private - no need to expose them. It's only important that you have a constructor without arguments.

但是请注意在Order类中没有参数的空构造函数(它是内部类)。他们是必需的。但是你可以把它们都变成私有的——不需要公开它们。只有有一个没有参数的构造函数才是重要的。

How to use (example):

File f = new File("whatever.xml");

Serializer ser = new Persister();
OrderObject orderObject = ser.read(OrderObject.class, f);

System.out.println(orderObject);

This code parses the Xml from file and prints the deserialized object.

这段代码从文件中解析Xml并打印反序列化对象。

Input Xml (as in your question):

输入Xml(如您的问题):

<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
  <order>
    <id>1</id>
    <id_address_delivery xlink:href="http://abc.com/add/1">1</id_address_delivery>
    <id_address_invoice xlink:href="http://abc.com/add/2">2</id_address_invoice>
  </order>
</prestashop>

Result (from println()):

结果从println()():

OrderObject{list=[Order{id=1, delivery=AdressDelivery{link=http://abc.com/add/1, value=1}, invoice=AdressInvoice{link=http://abc.com/add/2, value=2}}]}

Not clearly represented, but enough to see the result :-)

没有明确的表示,但足以看到结果:-)