Простая рамка пропускает мыльный конверт и тело

Я использую RetroFit и Simple XML Framework в Android для моделирования ответа SOAP, который выглядит следующим образом:

XML:

<soap:Envelope 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
    <BuslocationResponse 
        xmlns="AT_WEB">
        <Version>1.0</Version>
        <Responsecode>0</Responsecode>
        <Input>
            <Route>801</Route>
            <Direction>N</Direction>
        </Input>
        <Vehicles>
            <Vehicle>
                <Route>801</Route>
                <Direction>N</Direction>
                <Updatetime>09:42 PM</Updatetime>
                <Vehicleid>5007</Vehicleid>
                <Block>801-06</Block>
                <Adherance>-2</Adherance>
                <Adhchange>S</Adhchange>
                <Reliable>Y</Reliable>
                <Offroute>N</Offroute>
                <Stopped>N</Stopped>
                <Inservice>Y</Inservice>
                <Speed>20.61</Speed>
                <Heading> 3</Heading>
                <Routeid>44916</Routeid>
                <Positions>
                    <Position>30.221222,-97.765007</Position>
                    <Position>30.218363,-97.766747</Position>
                    <Position>30.215282,-97.768715</Position>
                    <Position>30.212505,-97.770485</Position>
                    <Position>30.204943,-97.774765</Position>
                    <Position>30.204035,-97.775078</Position>
                </Positions>
            </Vehicle>
        </Vehicles>
</BuslocationResponse>
</soap:Body>
</soap:Envelope>

На самом деле, все, что меня волнует, это коллекция транспортных средств. Кажется, я мог бы смоделировать только BusLocationResponse и пропустить мыльную оболочку и тело, объявив

Ява:

@Root(strict=false)
@Path("Envelope/Body/BuslocationResponse")
public class BusLocationResponse {

    @Element(name="Responsecode")
    public int responseCode;

    @ElementList
    @Path("Envelope/Body/BuslocationResponse/Vehicles")
    public List<CapVehicle> vehicles;

}

Это просто дает ошибку:

org.simpleframework.xml.core.ValueRequiredException: Unable to satisfy
@org.simpleframework.xml.Element(data=false, name=Responsecode, required=true,
type=void) on field 'responseCode' 

Что я здесь неправильно понимаю?


person Seth    schedule 08.06.2014    source источник
comment
Выбрать некоторые значения не так просто; +1   -  person ollo    schedule 15.06.2014


Ответы (2)


Вы не можете использовать @Path на @Root-элементе:

Аннотация Path используется для указания пути XML, в котором находится XML-элемент или атрибут.

( Источник )

Поскольку вам нужны вложенные данные откуда-то глубоко в xml, есть два решения:

  1. Сопоставьте всю структуру XML
  2. Используйте преобразователь это сопоставление сокращений до нескольких классов и сопоставление только тех

И вот что делать, если вы выберете № 2:

План

  • Класс SOAPEnvelope создает только корневой-элемент (<soap:Envelope>...</soap:Envelope>) и содержит список транспортных средств.
  • SOAPEnvelopeConverter реализует Converter для SOAPEnvelope - там сериализация сводится только к списку транспортных средств
  • Класс Vehicle содержит все данные этих элементов (включая класс Position для <Position>...</Position> элементов).
  • Класс Vehicles сопоставляет только тег vehicles (= список элементов транспортного средства).

(Имена не имеют соглашения)

Реализация

Я написал реализацию в качестве эталона, чтобы вы могли увидеть, как работает предложенное мной решение. Пожалуйста, добавьте проверку ошибок и т. д. Все поля данных здесь обрабатываются как String, замените их типы на правильные. Только десериализуется список транспортных средств, все остальные значения игнорируются. Конструкторы, геттеры/сеттеры и т. д. показаны только в том случае, если они необходимы для этого примера.

Список десериализованных транспортных средств хранится в объекте конверта. Это не лучший способ и используется только для примера. Пожалуйста, напишите здесь лучшую реализацию (например, введите класс для тела мыла, где вы можете управлять содержимым).

Примечание. Некоторые классы реализованы как внутренние классы — это необязательно, используйте код по своему усмотрению.

Класс SOAPEnvelope / Класс SOAPEnvelopeConverter (внутренний)

@Root(name = "Envelope")
@Namespace(prefix = "soap")
// Set the converter that's used for serialization
@Convert(value = SOAPEnvelope.SOAPEnvelopeConverter.class)
public class SOAPEnvelope
{
    // Keep the content of vehicles list here
    private Vehicles vehicles;


    public Vehicles getVehicles()
    {
        return vehicles;
    }

    protected void setVehicles(Vehicles vehicles)
    {
        this.vehicles = vehicles;
    }



    // The converter implementation for SOAPEnvelope
    public static class SOAPEnvelopeConverter implements Converter<SOAPEnvelope>
    {
        @Override
        public SOAPEnvelope read(InputNode node) throws Exception
        {
            SOAPEnvelope envelope = new SOAPEnvelope();
            InputNode vehiclesNode = findVehiclesNode(node); // Search the Vehicles list element

            if( vehiclesNode == null )
            {
                // This is bad - do something useful here
                throw new Exception("No vehicles node!");
            }

            /*
             * A default serializer is used to deserialize the full node. The
             * returned object is set into the envelops's object, where you can
             * get it through a get()-method.
             */
            Serializer ser = new Persister();
            envelope.setVehicles(ser.read(Vehicles.class, vehiclesNode));

            return envelope;
        }


        @Override
        public void write(OutputNode node, SOAPEnvelope value) throws Exception
        {
            // If you read (deserialize) only there's no need to implement this
            throw new UnsupportedOperationException("Not supported yet.");
        }


        private InputNode findVehiclesNode(InputNode rootNode) throws Exception
        {
            InputNode body = rootNode.getNext("Body");
            InputNode buslocationResponse = body.getNext("BuslocationResponse");

            InputNode next;

            while( ( next = buslocationResponse.getNext() ) != null )
            {
                if( next.getName().equals("Vehicles") == true )
                {
                    return next;
                }
            }

            return null;
        }
    }
}

Класс Vehicles

@Root(name = "Vehicles")
public class Vehicles
{
    // Maps the list of vehicles
    @ElementList(name = "Vehicles", inline = true)
    private List<Vehicle> vehicles;
}

Класс Vehicle

@Root(name = "Vehicle")
public class Vehicle
{
    // All values are of type String - please replace with proper types
    @Element(name = "Route")
    private String route;
    @Element(name = "Direction")
    private String direction;
    @Element(name = "Updatetime")
    private String updateTime;
    @Element(name = "Vehicleid")
    private String vehicleID;
    @Element(name = "Block")
    private String block;
    @Element(name = "Adherance")
    private String adherance;
    @Element(name = "Adhchange")
    private String adhchange;
    @Element(name = "Reliable")
    private String reliable;
    @Element(name = "Offroute")
    private String offroute;
    @Element(name = "Stopped")
    private String stopped;
    @Element(name = "Inservice")
    private String inservice;
    @Element(name = "Speed")
    private String speed;
    @Element(name = "Heading")
    private String heading;
    @Element(name = "Routeid")
    private String routeID;
    @ElementList(name = "Positions")
    private List<Position> postions;


    // A class to map the position elements
    @Root(name = "Position")
    public static class Position
    {
        @Text()
        private String position;
    }
}

Как использовать

final String xml = ...
Serializer ser = new Persister(new AnnotationStrategy()); // Annotation strategy is set here!

SOAPEnvelope soapEnvelope = ser.read(SOAPEnvelope.class, new StringReader(xml));

Здесь нет ничего особенного — требуется только AnnotationStrategy! Источник (2-й параметр ser.read() устанавливается по мере поступления вашего ввода. В этом примере мыло xml происходит из строки.

person ollo    schedule 14.06.2014
comment
Отличный ответ. Зачем использовать Persister по умолчанию для метода read()? Разве вы не хотели бы использовать его с AnnotationStrategy() для поддержки аннотаций автомобиля? - person Tom; 04.02.2016
comment
Здесь в этом нет необходимости, поскольку для обработки случаев достаточно простого Persister. Если ваш Persister в read()-методе должен использовать какой-либо пользовательский конвертер, вы должны использовать, например. AnnotationStrategy - но в этом примере это просто необязательно. - person ollo; 07.02.2016

простой способ - использовать @path, например, я хочу получить Route из узла Soap/Body/BuslocationResponse/Vehicles/Vehicle

Ответ.java

@Root(name = "soap:Envelope", strict = false)
public class Response {
   @Element(name = "Route")
   @Path("Body/BuslocationResponse/Vehicles/Vehicle")
   private int route;

   public int getRoute() {
    return route;
   }
}

Main.java

class Main {
public static void main(String args[]) {
    String xml = "<soap:Envelope \n" +
            "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
            "xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"\n" +
            "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
            "soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\n" +
            "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
            "<soap:Body>\n" +
            "    <BuslocationResponse \n" +
            "        xmlns=\"AT_WEB\">\n" +
            "        <Version>1.0</Version>\n" +
            "        <Responsecode>0</Responsecode>\n" +
            "        <Input>\n" +
            "            <Route>801</Route>\n" +
            "            <Direction>N</Direction>\n" +
            "        </Input>\n" +
            "        <Vehicles>\n" +
            "            <Vehicle>\n" +
            "                <Route>801</Route>\n" +
            "                <Direction>N</Direction>\n" +
            "                <Updatetime>09:42 PM</Updatetime>\n" +
            "                <Vehicleid>5007</Vehicleid>\n" +
            "                <Block>801-06</Block>\n" +
            "                <Adherance>-2</Adherance>\n" +
            "                <Adhchange>S</Adhchange>\n" +
            "                <Reliable>Y</Reliable>\n" +
            "                <Offroute>N</Offroute>\n" +
            "                <Stopped>N</Stopped>\n" +
            "                <Inservice>Y</Inservice>\n" +
            "                <Speed>20.61</Speed>\n" +
            "                <Heading> 3</Heading>\n" +
            "                <Routeid>44916</Routeid>\n" +
            "                <Positions>\n" +
            "                    <Position>30.221222,-97.765007</Position>\n" +
            "                    <Position>30.218363,-97.766747</Position>\n" +
            "                    <Position>30.215282,-97.768715</Position>\n" +
            "                    <Position>30.212505,-97.770485</Position>\n" +
            "                    <Position>30.204943,-97.774765</Position>\n" +
            "                    <Position>30.204035,-97.775078</Position>\n" +
            "                </Positions>\n" +
            "            </Vehicle>\n" +
            "        </Vehicles>\n" +
            "</BuslocationResponse>\n" +
            "</soap:Body>\n" +
            "</soap:Envelope>";

    try {
        Serializer serializer = new Persister();
        Response r = serializer.read(Response.class, xml);
        System.out.println("route: " + r.getRoute());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
} 

Результат:

/usr/lib/jvm/java-8-oracle/bin/java....
route: 801
Process finished with exit code 0
person vuhung3990    schedule 01.03.2016