我在Android中使用RetroFit
和简单XML
框架来模拟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'
我在这里误解了什么?
答案 0 :(得分:5)
您无法在@Path
上使用@Root
- 元素:
Path annotation用于指定XML元素或属性所在的XML路径。
(Source)
由于您希望嵌套数据来自xml深处,因此有两种解决方案:
如果您选择第2号,该怎么办:
SOAPEnvelope
类只构建 root -element(<soap:Envelope>...</soap:Envelope>
)并保存车辆列表SOAPEnvelopeConverter
为Converter
实施SOAPEnvelope
- 序列化仅限于车辆列表Vehicle
类包含这些元素的所有数据(包括Position
的{strong> <Position>...</Position>
Vehicles
仅映射vehicles
- 代码(=车辆元素列表)。(名称没有约定)
我已经编写了一个实现作为参考,因此您可以看到我建议的解决方案是如何工作的。请添加错误检查等。所有数据字段都在String
处理,请使用正确的类型替换其类型。 仅对车辆列表进行反序列化,忽略所有其他值。构造函数,getter / setter等仅显示为此示例所需的内容。
反序列化的车辆列表存储在信封的对象中。这不是最好的方法,仅用于举例。请在这里写一个更好的实现(例如,为肥皂体引入一个可以管理内容的类)。
注意:某些类是作为内部类实现的 - 这是可选的代码,您可以选择。
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
必需!源(ser.read()
的第二个参数设置为您的输入。在此示例中,soap xml来自一个字符串。
答案 1 :(得分:2)
简单的方法是使用@path,例如我想从节点($a) ? $b : $c;
获取Route
Response.java
Soap/Body/BuslocationResponse/Vehicles/Vehicle
Main.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;
}
}
结果:
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();
}
}
}