大宝的蛀牙

去年夏天的时候,早上吃完奶我经常带大宝出去晒太阳,经常会他买个包子吃;鉴于俺喜欢吃甜的,所以经常是爷俩一起吃糖包子或者豆沙包。后来就发现大宝的牙齿有点变绿了,不过社区医生很确定地说小孩不用刷牙,再加上外公的现身说法:外公从小爱吃甜的,而且到了十几岁都没刷过牙。于是从来也没给大宝刷过牙,直到大概去年10月份的时候,发现牙齿已经有点变黑了,于是给他刷了一下,一刷吓一跳:门牙中间已经有点蛀了,其他的牙齿能刷掉一些,但是也有点黑。

家里旁边就有个口腔医院,带大宝去看了一下,不过医生看见这么小的小孩就挠头,说这个确实是蛀牙,但是现在没法弄,多给他刷刷牙吧。于是先刷牙当成头等大事,每次吃完东西一定要漱口,吃完饭一定要刷牙,糖包子自然是不能吃了,别的甜的东西也要少吃。折腾了几个月,感觉好像有点控制住了。前阵子约上一个口腔医院的号,又带大宝去看了一下,医生说门牙上那个蛀牙洞太小了,转头比他大多了,没必要弄,还是继续刷牙吧。至于牙齿上的颜色,其实是色素沉淀,简单说就是吃完甜的东西又吃了有颜色的东西,糖把颜色给粘住了。还好,不过还是得要继续努力。

我觉得除了吃糖包子外,吃奶时间太长也是个可能的原因,以前大宝半夜醒来喜欢吃着奶睡觉,而且也不好好吃,一吃吃很久。还有一个原因可能是太阳晒得不够,略有点缺钙,而且牙齿锻炼得太少。

总结起来大概有那么几条:

1、吃完奶、吃完东西一定要漱口。

2、等稍微大一点开始吃辅食的时候就应该给他刷牙,指套或者牙刷,盐水或者牙膏,视情况而定。

3、少吃点甜的,比如说糖和饼干。

4、多让孩子晒晒太阳补补钙。

5、多锻炼锻炼孩子的咀嚼能力。

用SAX处理xml文件里的multiRef标签

开发某运营商的WebService订购关系通知接口,原先由VAC直接推送,现在中间加了一个网关,VAC推送网关,网关推送给我们,结果解析网关给过来的XML是出现了问题,一抓包发现是请求里头多了一些MultiRef的标签,不符合原先的WSDL定义。比如说userIdType,按正常来说应该是:

<userIdType type="soapenc:int">1</userIdType>

但是实际拿到的却是:

<userIdType href="#id1"/>

指向的是一个id1的标签,需要从下文里头去找出具体的值:

<multiRef id="id1" soapenc:root="0" soapenv:encodingStyle=" "http://schemas.xmlsoap.org/soap/encoding/">http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="soapenc:int">1</multiRef>

大概搜了一下,说其实是AXIS的一个特有的东西,甚至可以说是一个bug,AXIS2里头都已经取消了multiRef,要在AXIS1里头去掉这个也容易,只要改一下配置就可以了,于是联系网关的人,但是人家说这种int型就是用multiRef来传的,至于让他们改配置,自然不现实,人家说你用AXIS来解析好了。。。没办法,只能自己来弄了。

AXIS肯定不想用,这样的话就得大改。找了一下,网上有方法可以直接把格式转换一下,但是似乎略显复杂,而且接口相对于原来的程序而言也不太合适,于是还是决定自己解析。原先只是根据WSDL生成了请求对象,内容是使用SAX来解析的,大概的代码就是这么几行:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
VACReqHander handler = new VACReqHander();
parser.parse(in, handler);

主要就是这个VACReqHander,它继承了org.xml.sax.helpers.DefaultHandle,并且重载了其中的一下方法,这些方法会在适当的时候被parser调用。主要的方法有:

public void startDocument() //开始时被调用
public void startElement(String uri, String localName, String qName, Attributes attributes) //元素开始时被调用
public void characters(char[] ch, int start, int length) //取到值的时候被调用
public void endElement(String uri, String localName, String qName) //元素结束时被调用
public void endDocument() //结束时被调用

原先的实现比较简单,在startElement()里头把key放到一个全局的变量里头,即:key = qName,然后再characters()里头根据key来判断具体是哪个元素并且赋值,比如:

if ("userIdType".equals(key))
req.setUserIdType(Integer.valueOf(data));

但是这种只能处理标准格式的数据,如<key>value</key>,但是类似<userIdType href="#id1"/>这种数据的话characters()根本就没有被调用。大概debug了一下,发现这些都被放在startElement()attributes对象里头。这样就好办了,首先定义几个变量来保存数据:

String userIDtypeHref = null; //userIdType元素里的href对应的值,去掉#号,这里即id1
String multiRefID = null; //multiRef元素里的id对应的值,这里即id1
Hashtable<String,int> multiRefs = new Hashtable<String,Internet>(); //存储multiRef里头id和值的对应关系,这里即id1=1

然后在startElement()里头设置变量:

if(qName.equals("userIdType")){
userIDtypeHref = attributes.getValue("href").substring(1);
}
if(qName.equals("multiRef")){
multiRefID = attributes.getValue("id");
}

然后在 characters() 里取得multiRef里的value,并存储到Hashtable:

if ("multiRef".equals(nodeName)) {
if (refid!=null && isDigit(data))
{
multiRefs.put(multiRefID, Integer.valueOf(data));
}
}

最后在endDocument()设置一下userIdType的值:

if (req.getUserIdType()==0 && userIDtypeHref!=null)
req.setUserIdType(multiRefs.get(userIDtypeHref));

其他int类型的值,比如updateType可以同样处理