Android中如何手动将SOAP XML响应转换为Java对象?
手动解析ONVIF SOAP XML响应到Java对象(Android AOSP环境)
既然Android AOSP不包含JAX-WS和JAXB,手动解析确实是唯一可行的方案。针对你提到的ONVIF GetSystemDateAndTime SOAP响应,我来分享一套实用的实现步骤和代码示例:
首先,先补全你给出的SOAP响应片段(符合ONVIF标准格式),方便后续解析参考:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:tds="http://www.onvif.org/ver10/device/wsdl"> <SOAP-ENV:Body> <tds:GetSystemDateAndTimeResponse> <tds:SystemDateAndTime> <tds:DateTimeType>NTP</tds:DateTimeType> <tds:DaylightSavings>true</tds:DaylightSavings> <tds:TimeZone> <tds:TZ>CST-8</tds:TZ> </tds:TimeZone> <tds:UTCDateTime> <tds:Date> <tds:Year>2024</tds:Year> <tds:Month>5</tds:Month> <tds:Day>20</tds:Day> </tds:Date> <tds:Time> <tds:Hour>10</tds:Hour> <tds:Minute>30</tds:Minute> <tds:Second>45</tds:Second> </tds:Time> </tds:UTCDateTime> <tds:LocalDateTime> <tds:Date> <tds:Year>2024</tds:Year> <tds:Month>5</tds:Month> <tds:Day>20</tds:Day> </tds:Date> <tds:Time> <tds:Hour>18</tds:Hour> <tds:Minute>30</tds:Minute> <tds:Second>45</tds:Second> </tds:Time> </tds:LocalDateTime> </tds:SystemDateAndTime> </tds:GetSystemDateAndTimeResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
第一步:定义对应的数据模型类
我们需要创建和SOAP响应结构匹配的Java类,用来存储解析后的数据:
public class SystemDateTime { private String dateTimeType; private boolean daylightSavings; private TimeZone timeZone; private DateTime utcDateTime; private DateTime localDateTime; // Getters & Setters public String getDateTimeType() { return dateTimeType; } public void setDateTimeType(String dateTimeType) { this.dateTimeType = dateTimeType; } public boolean isDaylightSavings() { return daylightSavings; } public void setDaylightSavings(boolean daylightSavings) { this.daylightSavings = daylightSavings; } public TimeZone getTimeZone() { return timeZone; } public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } public DateTime getUtcDateTime() { return utcDateTime; } public void setUtcDateTime(DateTime utcDateTime) { this.utcDateTime = utcDateTime; } public DateTime getLocalDateTime() { return localDateTime; } public void setLocalDateTime(DateTime localDateTime) { this.localDateTime = localDateTime; } // 时区内部类 public static class TimeZone { private String tz; public String getTz() { return tz; } public void setTz(String tz) { this.tz = tz; } } // 日期时间内部类 public static class DateTime { private Date date; private Time time; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Time getTime() { return time; } public void setTime(Time time) { this.time = time; } // 日期子内部类 public static class Date { private int year; private int month; private int day; public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } } // 时间子内部类 public static class Time { private int hour; private int minute; private int second; public int getHour() { return hour; } public void setHour(int hour) { this.hour = hour; } public int getMinute() { return minute; } public void setMinute(int minute) { this.minute = minute; } public int getSecond() { return second; } public void setSecond(int second) { this.second = second; } } } }
第二步:用XmlPullParser实现解析逻辑
Android AOSP原生支持XmlPullParser,它是轻量高效的XML解析器,非常适合这种场景:
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.io.InputStream; public class SoapResponseParser { public static SystemDateTime parseGetSystemDateAndTimeResponse(InputStream inputStream) throws XmlPullParserException, IOException { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(inputStream, "UTF-8"); int eventType = parser.getEventType(); SystemDateTime systemDateTime = null; SystemDateTime.TimeZone timeZone = null; SystemDateTime.DateTime utcDateTime = null; SystemDateTime.DateTime localDateTime = null; SystemDateTime.DateTime.Date date = null; SystemDateTime.DateTime.Time time = null; while (eventType != XmlPullParser.END_DOCUMENT) { String tagName = parser.getName(); String namespace = parser.getNamespace(); final String ONVIF_DEVICE_NAMESPACE = "http://www.onvif.org/ver10/device/wsdl"; switch (eventType) { case XmlPullParser.START_TAG: // 用命名空间判断更可靠,避免前缀变化影响解析 if (ONVIF_DEVICE_NAMESPACE.equals(namespace)) { switch (tagName) { case "SystemDateAndTime": systemDateTime = new SystemDateTime(); break; case "DateTimeType": if (systemDateTime != null) { systemDateTime.setDateTimeType(parser.nextText().trim()); } break; case "DaylightSavings": if (systemDateTime != null) { systemDateTime.setDaylightSavings(Boolean.parseBoolean(parser.nextText().trim())); } break; case "TimeZone": timeZone = new SystemDateTime.TimeZone(); break; case "TZ": if (timeZone != null && systemDateTime != null) { timeZone.setTz(parser.nextText().trim()); systemDateTime.setTimeZone(timeZone); } break; case "UTCDateTime": utcDateTime = new SystemDateTime.DateTime(); break; case "LocalDateTime": localDateTime = new SystemDateTime.DateTime(); break; case "Date": date = new SystemDateTime.DateTime.Date(); break; case "Year": if (date != null) { date.setYear(Integer.parseInt(parser.nextText().trim())); } break; case "Month": if (date != null) { date.setMonth(Integer.parseInt(parser.nextText().trim())); } break; case "Day": if (date != null) { date.setDay(Integer.parseInt(parser.nextText().trim())); // 将日期关联到当前的DateTime对象 if (utcDateTime != null && utcDateTime.getDate() == null) { utcDateTime.setDate(date); } else if (localDateTime != null && localDateTime.getDate() == null) { localDateTime.setDate(date); } } break; case "Time": time = new SystemDateTime.DateTime.Time(); break; case "Hour": if (time != null) { time.setHour(Integer.parseInt(parser.nextText().trim())); } break; case "Minute": if (time != null) { time.setMinute(Integer.parseInt(parser.nextText().trim())); } break; case "Second": if (time != null) { time.setSecond(Integer.parseInt(parser.nextText().trim())); // 将时间关联到当前的DateTime对象 if (utcDateTime != null && utcDateTime.getTime() == null) { utcDateTime.setTime(time); } else if (localDateTime != null && localDateTime.getTime() == null) { localDateTime.setTime(time); } } break; } } break; case XmlPullParser.END_TAG: if (ONVIF_DEVICE_NAMESPACE.equals(namespace)) { switch (tagName) { case "UTCDateTime": if (systemDateTime != null) { systemDateTime.setUtcDateTime(utcDateTime); } break; case "LocalDateTime": if (systemDateTime != null) { systemDateTime.setLocalDateTime(localDateTime); } break; } } break; } eventType = parser.next(); } return systemDateTime; } }
一些关键注意事项
- 命名空间判断:上面的代码使用了ONVIF设备服务的命名空间来判断标签,比直接匹配带前缀的标签更可靠,因为有些设备可能会用不同的前缀(比如
dev代替tds) - 异常处理:在AOSP环境中,要确保捕获
IOException和XmlPullParserException,避免未处理的异常导致进程崩溃 - 扩展性:如果需要解析其他ONVIF SOAP响应,可以复用这套结构:先定义对应的数据类,再扩展解析逻辑中的标签判断分支
- 测试验证:可以用模拟的SOAP响应输入流来测试解析逻辑,确保所有字段都能正确映射
内容的提问来源于stack exchange,提问作者kiran Biradar
相关产品推荐
相关产品推荐

