在这里,我所使用的是网易有道的接口,把网址http://www.youdao.com/smartresult-xml /search.s?type=id&q= + 要查询的身份证号,粘贴到浏览器上打开,可以看到返回的是一个表示结果的XML文件。目前未发现 使用限制。
首先在浏览器 上测试一个有效的身份证号,查看源文件,可以看到返回的信息中,有四个元素是我们需要的,即code身份证号码,location身份证发证地,birthday生日,gender性别。再试一下查询无效的身份证号,只有一个<smartresult/>。
创建一个类,表示身份证信息,内容如下(get及set方法省略),为方便测试,还得覆写toString方法,将所有内容打印出来:
[java] view plaincopy
1. public class IdCard {
2.
3. private String id;
4. private String location;
5. private String birthday;
6. private String gender;
7. }
然后从网上下载查询返回的结果,并判断该身份证号是否有效。在前面的,已经知道如果查询不到身份证信息,将返回<smartresult />,否则,返回的是<smartresult> 身份证详细内容</smartresult>。实现的代码如下:
[java] view plaincopy
1. /**
2. * 根据身份证号查询相关信息。
3. *
4. * @param id
5. * 身份证号
6. */
7. public IdCard query(String id) {
8. String info = null;
9. try {
10. info = getStringFromUrl(
11. "http://www.youdao.com/smartresult-xml/search.s?type=id&q="
12. + id, "gbk");
13. } catch (MalformedURLException e) {
14. e.printStackTrace();
15. } catch (IOException e) {
16. e.printStackTrace();
17. }
18. if ( info == null || info.contains("<smartresult/>")) {
19. return null;
20. }
21. // System.out.println(info);
22. IdCard idCard = parseXML(info);
23. // System.out.println(idCard);
24. return idCard;
25. }
该方法接收一个表示身份证号的字符串,与查询地址拼接,然后获取该地址的数据,如果返回的是null指针,表示无法下载到数据,如果返回的数据 库包含了<smartresult/>标签,则说明查询不到结果。在上面的代码中,由于自己只需要查询到身份证号码的结果的情况并进行进一步 的操作,所对将另两种作一起判断,返回空指针。这个亦可在if语句中分别判断并给出不同的提示。getStringFromUrl是自己写的一个方法,共 有两个参数,第一个表示请求的网址,第二个表示编码格式。该方法实现也比较简单,内容如下:
[java] view plaincopy
1. /**
2. * 根据URL名得到输入流。
3. *
4. * @param urlStr
5. * URL名。
6. *
7. * @return 得到的输入流。
8. *
9. * @throws MalformedURLException
10. * 如果字符串指定未知协议。
11. * @throws IOException
12. * 如果发生 I/O 错误。
13. */
14. private String getStringFromUrl(String urlStr, String charsetName) throws MalformedURLException, IOException {
15. URL url = new URL(urlStr);
16. HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
17. InputStream in = urlConn.getInputStream();
18. String string = InputStreamToString(in, charsetName);
19. return string;
20. }
在上面的方法中,得到的是InputStream类型的对象,还需要转换成String类型。这个可以在网上找,代码如下:
[java] view plaincopy
1. /**
2. * 将InputStream转换成String
3. * @param urlStr
4. * @param charsetName 字符集名
5. * @return
6. */
7. private String InputStreamToString ( InputStream in, String charsetName) {
8.
9. if (in == null) {
10. return null;
11. }
12. StringBuilder sb = new StringBuilder();
13. String temp = null;
14. try {
15. BufferedReader bf = new BufferedReader(new InputStreamReader(in, charsetName));
16. while ((temp = bf.readLine()) != null) {
17. sb.append(temp).append("\n");
18. }
19. } catch (IOException e) {
20. e.printStackTrace();
21. }
22. return sb.toString();
23. }
到这里,我们已经能得到一个String类型的结果了。下面将对这个结果进行解析。由于内容较简单,也可对结果用正则表示式提取数据。我这里用 到的是XMLReader类,来解析XML文件。用这种方法,需要实现ContentHandler接口。下面的代码中,是通过继承 DefaultHandler类并重写里面的方法来实现的。
[java] view plaincopy
1. public class MyContentHandler extends DefaultHandler {
2.
3. private IdCard idCard;
4. private String tagName;
5.
6. public MyContentHandler(IdCard idCard) {
7. this.idCard = idCard;
8. }
9.
10. @Override
11. public void characters(char[] ch, int start, int length)
12. throws SAXException {
13. String tmp = new String(ch, start, length);
14. if (tagName.equals("code")) {
15. idCard.setId(tmp);
16. } else if (tagName.equals("location")) {
17. idCard.setLocation(tmp);
18. } else if (tagName.equals("birthday")) {
19. idCard.setBirthYear(tmp.substring(0, 4));
20. idCard.setBirthMonth(tmp.substring(4, 6));
21. idCard.setBirthDay(tmp.substring(6, 8));
22. } else if (tagName.equals("gender")) {
23. idCard.setGender(tmp);
24. }
25. }
26.
27. @Override
28. public void endDocument() throws SAXException {
29. super.endDocument();
30. }
31.
32. @Override
33. public void endElement(String uri, String localName, String qName)
34. throws SAXException {
35. tagName = "";
36. }
37.
38. @Override
39. public void startDocument() throws SAXException {
40. super.startDocument();
41. }
42.
43. @Override
44. public void startElement(String uri, String localName, String qName,
45. Attributes attributes) throws SAXException {
46. this.tagName = localName;
47. if ("".equals(localName)) {
48. this.tagName = qName;
49. }
50. // System.out.println("uri:" + uri + ", localName:" + localName + ", qName:" + qName);
51. }
52.
53. public IdCard getIdCard() {
54. return idCard;
55. }
56. }
上面的代码可能还不完善。其中的成员变量tagName,是为了对读到的元素进行标记。关于这段代码,可以参数mars-droid第一季视频中XML文件那一集。在这里其中在startElement方法中,我对tagName的赋值是这样的:
[java] view plaincopy
1. this.tagName = localName;
2. if ("".equals(localName)) {
3. this.tagName = qName;
4. }
看起来貌似很麻烦。这个也是我一时想到的。我在使用的时候悲剧地发现,第一次使用时读到的如code等元素,是赋值在qName中的,但是移植到Android中时,貌似却是读到localName的,又不知它会不会变成赋值到qName中去,只好用这个方法了。
实现了ContentHandler之后,下面对其使用的代码如下:
[java] view plaincopy
1. /**
2. * 得析得到的XML字符串的信息
3. * @param info
4. * @return
5. */
6. private IdCard parseXML(String info) {
7. IdCard idCard = new IdCard();
8.
9. try {
10. XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
11. MyContentHandler contentHandler = new MyContentHandler(idCard);
12. xmlReader.setContentHandler(contentHandler);
13. xmlReader.parse(new InputSource(new StringReader(info)));
14. } catch (Exception e) {
15. e.printStackTrace();
16. }
17. return idCard;
18. }
这样就得到了IdCard对象了。
以上内容中,如果有问题,或有更好的实现方法,还望大家指教。我是菜鸟。