Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parsing the XML by SimpleXML

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.

<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

@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

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)
.
.
like image 205
Haresh Chaudhary Avatar asked Jun 18 '13 10:06

Haresh Chaudhary


People also ask

How do I parse an XML array?

Step 1: Creating an XML file (Optional): Create an XML file which need to convert into the array. <? xml version = '1.0' ?> Step 2: Convert the file into string: XML file will import into PHP using file_get_contents() function which read the entire file as a string and store into a variable.

What is parsing the XML?

XML parsing is the process of reading an XML document and providing an interface to the user application for accessing the document. An XML parser is a software apparatus that accomplishes such tasks.

How do you parse an XML string in Python?

There are two ways to parse the file using 'ElementTree' module. The first is by using the parse() function and the second is fromstring() function. The parse () function parses XML document which is supplied as a file whereas, fromstring parses XML when supplied as a string i.e within triple quotes.


1 Answers

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.

Please see JavaDoc of @Attribute:

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

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!

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.

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.

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.

Input Xml (as in your question):

<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()):

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 :-)

like image 135
ollo Avatar answered Sep 28 '22 04:09

ollo