“Web”目录存档

Android4.0系统浏览器支持window.performance API了

2012年01月31日,星期二

4.0系统浏览器支持window.performance API了

window.performance API是HTML5规范的一部分,
window.performance规范的官方文档在:

https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html

目前还是草稿阶段,中文介绍可以参考:

http://www.cnblogs.com/_franky/archive/2011/11/07/2238980.html

webkit的测试用例和属性列表可以参考:

http://svn.webkit.org/repository/webkit/trunk/LayoutTests/fast//dom/Window/window-properties-performance.html

http://svn.webkit.org/repository/webkit/trunk/LayoutTests/fast//dom/Window/window-properties-performance-expected.txt

Android4.0系统自带的浏览器实现了这一规范,并且还扩展实现window.performance.memory。

通过JavaScript实际测试结果如下:
window.performance.memory=[object MemoryInfo]
window.performance.timing=[object PerformanceTiming]
window.performance.navigation=[object PerformanceNavigation]
window.performance.timing.connectStart=1328016452403
window.performance.timing.responseStart=1328016452403
window.performance.timing.domLoading=1328016453857
window.performance.timing.connectEnd=1328016452403
window.performance.timing.domInteractive=0
window.performance.timing.fetchStart=1328016452403
window.performance.timing.secureConnectionStart=0
window.performance.timing.domainLookupStart=1328016452403
window.performance.timing.responseEnd=0
window.performance.timing.requestStart=1328016452403
window.performance.timing.loadEventEnd=0
window.performance.timing.domComplete=0
window.performance.timing.redirectStart=0
window.performance.timing.unloadEventEnd=1328016453646
window.performance.timing.domContentLoadedEventStart=0
window.performance.timing.domContentLoadedEventEnd=0
window.performance.timing.domainLookupEnd=1328016452403
window.performance.timing.navigationStart=1328016452402
window.performance.timing.unloadEventStart=1328016453646
window.performance.timing.loadEventStart=0
window.performance.timing.redirectEnd=0
window.performance.navigation.redirectCount=0
window.performance.navigation.type=1
window.performance.navigation.TYPE_NAVIGATE=0
window.performance.navigation.TYPE_RELOAD=1
window.performance.navigation.TYPE_BACK_FORWARD=2
window.performance.navigation.TYPE_RESERVED=255
window.performance.memory.totalJSHeapSize=0
window.performance.memory.usedJSHeapSize=0
window.performance.memory.jsHeapSizeLimit=0

PS:Android从2.1版本还扩展实现了navigator.connection:
通过JavaScript测试结果如下:
navigator.connection.type=4
navigator.connection.UNKNOWN=0
navigator.connection.ETHERNET=1
navigator.connection.=2
navigator.connection.CELL_2G=3
navigator.connection.CELL_3G=4

 

Tags: , ,

手机wap网站开发过程中通过dtd校验来检查wap1.0和wap2.0的页面语法

2011年08月21日,星期日

手机wap网站开发过程中通过dtd校验来检查wap1.0和wap2.0的页面语法

对手机wap网站的wap1.0和wap2.0页面内容进行dtd的校验非常有价值,既可以保证页面对移动终端的兼容性,也能促使开发人员写出高质量的代码。

以前早期在做普通web页面开发的时候,对html的语法一知半解就开搞,标签不闭合,嵌套错误等问题从来没注意过,只管在IE6里打开能正常显示即可,
结果带来的后果就是在页面某个位置需要插入一段新内容时,整个页面就错位了,变得非常难看,也不知道怎么样来搞好,痛苦万分。

后来进行的是wap页面开发,wap页面用的是wap1.0的xml,加上各种山寨手机对wap页面的解析可不像电脑上的浏览器那样可以对错误的写法进行兼容,于是各种兼容性问题就出来了。
因此学会了用m3gate打开页面进行检查,只有m3gate打开时不出错的页面,才能放心的在各种山寨上正常显示而不出错。
再到后来,经过学习和总结,发现m3gate的检查其实和dtd校验的效果是一样的,于是摸索出通过dtd校验来发现标签嵌套错误等问题。

移动终端的发展是日新月异,很快就进入到了wap2.0时代,当然这个时候的手机浏览器对wap2.0的兼容性就好多了。
一些小的错误,也能兼容掉,但是难免也出现莫名其妙的错误,由于wap2.0的xml元素定义用的也还是dtd,因此继续用dtd校验来搞定。

1.0和wap2.0的自动化监控校验流程如下:
测试工具访问各个页面,获取对应的xml内容,保存为字符串,然后将页面的dtd声明部分,替换为对应的本地声明映射(这样避免联网获取dtd文件而影响性能),
生成新的字符串,然后使用java的xml parser进行解析,解析过程中如果有抛出各种异常,那就是把页面内容有错的地方全部揪出来了,再通知开发人员进行页面内容的bug修复。
通常比如img元素缺少alt属性等问题都可以及时发现。

正式环境则通过自动化监控脚本定期访问业务进行检查。

进行dtd校验的相关代码如下:

1.将远程的dtd等实体解析映射到本地的LocalEntityResolver(自动化监控中是通过字符串替换来将dtd的声明替换为本地路径,我是直接通过EntityResolver来进行映射):

[code]
package com.lizongbo.xml;

import java.io.IOException;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* 将xml组件依赖的远程的schema文件都映射到本地
*
* @author lizongbo
*
*/
public class LocalEntityResolver implements EntityResolver {

@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
System.out.println("publicId==" + publicId + ",systemId==" + systemId);
if ("-//W3C// XHTML 1.0 Strict//EN".equals(publicId)) {
String url = "/com/lizongbo//validation/dtds/www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
System.out.println(systemId + " LocalEntityResolver yyyy map to:"
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
if (systemId != null) {
String ids[] = new String[] { "/xhtml-attribs-1.mod",
"/xhtml-notations-1.mod", "/xhtml-datatypes-1.mod",
"/xhtml-qname-1.mod", "/xhtml-mobile10-model-1.mod",
"/xhtml-mobile10-model-1.mod", "xhtml-charent-1.mod",
"/xhtml-symbol.ent", "/xhtml-lat1.ent",
"/xhtml-special.ent", "/xhtml-inlstruct-1.mod",
"/xhtml-inlphras-1.mod", "/xhtml-blkstruct-1.mod",
"xhtml-blkphras-1.mod", "/xhtml-lat1.ent",
"/xhtml-lat1.ent" };

for (int i = 0; i < ids.length; i++) {
if (systemId.endsWith(ids[i])) {
String url = "/com/lizongbo/web/validation/dtds/www.w3.org/xhtml-modularization/DTD/"
+ systemId.substring(systemId.lastIndexOf("/") + 1);
System.out.println(" local " + systemId + " try map to:"
+ url);
if (String.class.getResource(url) == null) {
url = "/com/lizongbo/web/validation/dtds/www.w3.org/TR/xhtml-modularization/DTD/"
+ systemId
.substring(systemId.lastIndexOf("/") + 1);
System.out.println(" local " + systemId
+ " retry map to:" + url);
}
if (String.class.getResource(url) == null) {
url = "/com/lizongbo/web/validation/dtds/www.wapforum.org/DTD/"
+ systemId
.substring(systemId.lastIndexOf("/") + 1);
System.out.println(" local " + systemId
+ " retry map to:" + url);
}
System.out.println("try get "
+ String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
}
if (systemId.endsWith(".xsd")) {
String url = "/com/lizongbo/web/validation/xsds/"
+ systemId.replace("http://", "");
System.out.println(systemId + " LocalEntityResolver 22 map to:"
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
} else {
String url = "/com/lizongbo/web/validation/dtds/"
+ systemId.replace("http://", "");
System.out.println(systemId + " LocalEntityResolver 11 map to:"
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) == null) {
url = "/com/lizongbo/web/validation/dtds/www.w3.org/TR/xhtml-modularization/DTD/"
+ systemId.replace("http://", "");
System.out.println(" local " + systemId + " retry map to:"
+ url);
}
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
}
return null;
}
}

[/code]

2.实际校验的代码:
[code]
package com.lizongbo.xml;

import java.io.*;
import java.net.*;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.*;

/**
* DTD校验工具类
*
* @author lizongbo
*
*/
public class DTDUtil {

/**
* @param args
* @throws SAXException
* @throws ParserConfigurationException
*/
public static void main(String[] args) throws SAXException,
ParserConfigurationException {
String urls[] = new String[] { "http://3g.sina.com.cn/?vt=1&pos=200",// 新浪wap1.0
"http://3g.sina.com.cn/?vt=3&pos=200",// 新浪wap2.0
"http://wap.sohu.com/?nid=1&v=1",// 搜狐
"http://wap.sohu.com/?nid=1&v=3",// 搜狐
"http://info50.3g.qq.com/g/s?aid=index&g_ut=1",// 手机腾讯网wap1.0
"http://info50.3g.qq.com/g/s?aid=index&g_ut=2", // 手机腾讯网wap2.0
};
for (int i = 0; i < urls.length; i++) {
try {
String urlStr = urls[i];
String xml = downloadUrl(urlStr, null, "UTF-8");
// System.out.println(xml);
validateWap(xml);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Over");
}

/**
* 通过dtd校验wap2.0页面内容,如果抛出异常则说明页面内容有错
*
* @param xml
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public static void validateWap(String xml)
throws ParserConfigurationException, SAXException, IOException {
// //xml = setDTDforWap20(xml);
// //System.out.println(xml);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new LocalEntityResolver());
Document doc = db.parse(new InputSource(new StringReader(xml)));
System.out.println(doc.getFirstChild());
}

public static String downloadUrl(String urlStr, String referer,
String encoding) throws Exception {
String line = "";
StringBuilder sb = new StringBuilder();
HttpURLConnection httpConn = null;
try {
URL url = new URL(urlStr);
System.out.println(urlStr);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
"proxy.lizongbo.com", 8080));
proxy = Proxy.NO_PROXY;
httpConn = (HttpURLConnection) url.openConnection(proxy);
httpConn.setRequestProperty("User-Agent", "Nokia");
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
httpConn.setRequestMethod("GET");
if (referer != null) {
httpConn.setRequestProperty("Referer", referer);
}
httpConn.setConnectTimeout(1000);
BufferedReader in = null;
if (httpConn.getResponseCode() != 200) {
System.err.println("error:" + httpConn.getResponseMessage());
in = new BufferedReader(new InputStreamReader(
httpConn.getErrorStream(), "UTF-8"));
} else {
in = new BufferedReader(new InputStreamReader(
httpConn.getInputStream(), "UTF-8"));
}
while ((line = in.readLine()) != null) {
sb.append(line).append('\n');
}
System.out.println(httpConn.getHeaderFields());
// 关闭连接
httpConn.disconnect();
return sb.toString();
} catch (Exception e) {
// 关闭连接
if (httpConn != null) {
try {
httpConn.disconnect();
} catch (Exception e2) {
// TODO: handle exception
}
}
System.out.println(e.getMessage());
throw e;
}
}
}

[/code]

通过上面的例子,可以看到新浪,搜狐,手机腾讯网的wap1.0都校验ok。
而新浪的wap2.0(3G版)使用的声明不是http://www.wapforum.org/DTD/xhtml-mobile10.dtd,却是:xhtml1-strict.dtd

按xhtml1-strict.DTD校验的出错信息为:
Error: URI=null Line=127: Attribute “width” must be declared for element type “input”.
Error: URI=null Line=127: Attribute “height” must be declared for element type “input”.
Error: URI=null Line=127: The content of element type “form” must match “(p|h1|h2|h3|h4|h5|h6|div|ul|ol|dl|pre|hr|blockquote|address|fieldset|table|noscript|ins|del|script)*”.
Error: URI=null Line=155: The content of element type “form” must match “(p|h1|h2|h3|h4|h5|h6|div|ul|ol|dl|pre|hr|blockquote|address|fieldset|table|noscript|ins|del|script)*”.
Error: URI=null Line=236: Attribute value “gototop” of type ID must be unique within the document.
搜狐的wap2.0(彩版)虽然使用的dtd声明是:http://www.wapforum.org/DTD/xhtml-mobile10.dtd,但是页面内容中却使用xhtml1所定义的元素。
按xhtml-mobile10.dtd校验的出错信息为:
Error: URI=null Line=63: Element type “script” must be declared.
Error: URI=null Line=99: The content of element type “div” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|form|fieldset|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|i|b|big|small|a|img|object|input|select|textarea|label)”.
Error: URI=null Line=100: Attribute “name” must be declared for element type “form”.
Error: URI=null Line=100: Attribute “accept-charset” must be declared for element type “form”.
Error: URI=null Line=107: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=108: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=109: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=110: The content of element type “form” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|fieldset)+”.
Error: URI=null Line=112: Element type “font” must be declared.
Error: URI=null Line=112: The content of element type “div” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|form|fieldset|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|i|b|big|small|a|img|object|input|select|textarea|label)”.

手机腾讯网的wap2.0使用xhtml-mobile10.dtd进行校验,出错信息最少,只有一条:
Error: URI=null Line=141: The content of element type “form” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|fieldset)+”.

 

 

Tags: , , , , , , ,

从google的json接口获取地理位置信息的Java代码

2011年05月5日,星期四

从google的json接口获取地理位置信息的Java代码

google 提供了公开的接口,通过,这个接口,根据gps或基站信息或wifi热点信息来获取当前位置的地理信息.
gps信息是经纬度,基站信息是基站的cellid等信息,wifi热点信息是wifi的mac地址是热点名字,信号强度等。
因此可以通过java程序获取相应信息,在LBS项目中可以用上:

api接口定义描述在:

http://code.google.com/p/gears/wiki/GeolocationAPI

Java代码如下:

[code]

package com.lizongbo.;

import .io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;

import com.lizongbo.org..JSONArray;
import com.lizongbo.org.json.JSONException;
import com.lizongbo.org.json.JSONObject;

/**
* 从google的json接口获取地理位置信息的代码
*
* @author lizongbo
*
*/
public class GeoTest {

/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String url = "http://www.google.com/loc/json";
JSONObject json = new JSONObject();
json.put("version", "1.1.0");
json.put("host", "maps.618119.com");
json.put("home_mobile_country_code", 460);// 国家代码
json.put("home_mobile_network_code", 0);// 移动运营商代码
json.put("radio_type", "gsm");
json.put("carrier", "lizongbo");
json.put("request_address", true);
json.put("address_language", "zh_CN");
JSONArray jsoncells = new JSONArray();
json.put("cell_towers", jsoncells);
JSONArray jsonwifis = new JSONArray();
json.put("_towers", jsonwifis);
JSONObject jsoncell = new JSONObject();
jsoncell.put("mobile_country_code", 460);// 国家代码,mcc
jsoncell.put("mobile_network_code", 0);// 移动运营商代码,mnc
jsoncell.put("location_area_code", 9364);// 位置区域代码,lac
jsoncell.put("cell_id", "3851");// 移动基站id
// jsoncell.put("age", 0);
// jsoncell.put("signal_strength", -70);
// jsoncell.put("timing_advance", 7777);
jsoncells.put(jsoncell);
JSONObject jsonwifi = new JSONObject();
// jsonwifi.put("mac_address", "00-11-22-33-44-55");
// jsonwifi.put("signal_strength", 8);
// jsonwifi.put("age", 0);
// jsonwifis.put(jsonwifi);
// jsonwifi = new JSONObject();
jsonwifi.put("mac_address", "00-55-44-33-22-11");//
jsonwifi.put("ssid", "TPLINK_618119");// 无线路由器的名字
jsonwifi.put("signal_strength", 8);// 信号强度
jsonwifi.put("age", 0);
// jsonwifis.put(jsonwifi);

System.out.println(json.toString());
System.out.println(downloadUrlbyPOST(url, json.toString(), null,
"UTF-8"));

}

public static String downloadUrlbyPOST(String urlStr, String query,
String referer, String encoding) throws Exception {
String line = "";
StringBuilder sb = new StringBuilder();
HttpURLConnection httpConn = null;
try {
URL url = new URL(urlStr);
System.out.println(urlStr + "?" + query);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
"proxy.lizongbo.com", 8080));
proxy = Proxy.NO_PROXY;
httpConn = (HttpURLConnection) url.openConnection(proxy);
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
httpConn.setRequestMethod("POST");
if (referer != null) {
httpConn.setRequestProperty("Referer", referer);
}
httpConn.setConnectTimeout(5000);
// httpConn.getOutputStream().write(
// java.net.URLEncoder.encode(query, "UTF-8").getBytes());
httpConn.getOutputStream().write(query.getBytes());
httpConn.getOutputStream().flush();
httpConn.getOutputStream().close();

BufferedReader in = null;
if (httpConn.getResponseCode() != 200) {
System.err.println("error:" + httpConn.getResponseMessage());
in = new BufferedReader(new InputStreamReader(httpConn
.getErrorStream(), "UTF-8"));
} else {
in = new BufferedReader(new InputStreamReader(httpConn
.getInputStream(), "UTF-8"));
}
while ((line = in.readLine()) != null) {
sb.append(line).append('\n');
}
// 关闭连接
httpConn.disconnect();
return sb.toString();
} catch (Exception e) {
// 关闭连接
httpConn.disconnect();
System.out.println(e.getMessage());
throw e;
}
}
}

[/code]
运行结果如下:
{“address_language”:”zh_CN”,”wifi_towers”:[],”host”:”maps.618119.com”,”radio_type”:”gsm”,”home_mobile_country_code”:9364,”carrier”:”lizongbo”,”home_mobile_network_code”:460,”cell_towers”:[{"mobile_network_code":0,"cell_id":"3851","mobile_country_code":460,"location_area_code":9364}],”request_address”:true,”version”:”1.1.0″}
http://www.google.com/loc/json?{“address_language”:”zh_CN”,”wifi_towers”:[],”host”:”maps.618119.com”,”radio_type”:”gsm”,”home_mobile_country_code”:9364,”carrier”:”lizongbo”,”home_mobile_network_code”:460,”cell_towers”:[{"mobile_network_code":0,"cell_id":"3851","mobile_country_code":460,"location_area_code":9364}],”request_address”:true,”version”:”1.1.0″}
{“location”:{“latitude”:22.522185,”longitude”:113.925618,”address”:{“country”:”中国”,”country_code”:”CN”,”region”:”广东省”,”city”:”深圳市”,”street”:”滨海大道辅路”},”accuracy”:620.0},”access_token”:”2:618119:lizongbo”}

试了一下把无线路由器的mac地址发到 https://www.google.com/loc/json ,google果然返回很准的定位看来google是把我用手机测试定位的时候就把数据采集分析好了,确实强大。

Tags: , , , , ,