访问量较大,1小时几十万次, 单个xml文件2M左右,用dom4j等开源类,cpu占用太高,基本是parse方法占用的。
自己写了个简单的解析方法,只用indexOf和substring, 大概快1/3到一半的样子。
【重要】【前提】,XML是格式完整的,正确的,不能有命名空间。 另外,Element名称不要重复,各层次之间不要有重名的 因为纯粹用indexOf查找的,没有层次概念。
怎么用看main方法即可。 ------------------------------
package com.xxx.xml;
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry;
public class StrElement {
// <OriginDestinationOption ElapsedTime="125"> // <FlightSegment DepartureDateTime="2017-12-12T08:50:00" // ArrivalDateTime="2017-12-12T11:55:00" StopQuantity="0" FlightNumber="896" // ResBookDesigCode="N" ElapsedTime="125"> // <DepartureAirport LocationCode="PVG" TerminalID="1"/> // <ArrivalAirport LocationCode="ICN"/> // <OperatingAirline Code="KE" FlightNumber="896"/> // <Equipment AirEquipType="332"/> // <MarketingAirline Code="KE"/> // <MarriageGrp>O</MarriageGrp> // <DepartureTimeZone GMTOffset="8"/> // <ArrivalTimeZone GMTOffset="9"/> // <TPA_Extensions> // <eTicket Ind="true"/> // <Mileage Amount="506"/> // </TPA_Extensions> // </FlightSegment> // </OriginDestinationOption>
/** * XML文本. */ private String xml = null;
/** * 属性Map. */ private Map<String, String> attrMap = null;
/** * 构造方法. * * @param xml */ public StrElement(String xml) { this.xml = xml; }
/** * 查找下级元素(假设标签名不重复,现在没管层级,哈哈). * * @param tagName * @return */ public List<StrElement> select(String tagName) {
List<StrElement> list = new ArrayList<StrElement>();
// <AAA xx=""/><BBB><CCC yy=""/></BBB>
// <AAA ...>...</AAA>
// <StopAirports><StopAirport>...</StopAirport><StopAirport // Code="yyy"../></StopAirports> String startTagName = "<" + tagName; String endTagName = "</" + tagName + ">"; int indexA = xml.indexOf(startTagName); while (indexA != -1) {
// 看tagName后的那个字符 int indexThat = indexA + startTagName.length(); if (indexThat > xml.length()) { break; }
// <aaa>,<aaa/><aaa x="1"> // ...<ABCD>..<ABC>..</ABCD> char cThat = xml.charAt(indexThat); if (cThat == '>' || cThat == '/' || cThat == ' ') { // 通过 } else { // 说明,查找ABC时,误找到了ABCD,需要跳过 indexA = xml.indexOf(startTagName, indexThat + 1); continue; }
// 查找">",然后看前一个字符是不是"/" int indexB = xml.indexOf(">", indexA + tagName.length()); char c = xml.charAt(indexB - 1); if (c == '/') { // 如果是/>,那么说明是自关闭的tag String oneRow = xml.substring(indexA, indexB + 1); list.add(new StrElement(oneRow));
} else {
// 截取一个 indexB = xml.indexOf(endTagName, indexA + tagName.length()); indexB += tagName.length() + 3; String oneRow = xml.substring(indexA, indexB); list.add(new StrElement(oneRow)); }
// 下一个 indexA = xml.indexOf(startTagName, indexB); } return list; }
/** * 获取指定名字的第一个子元素. * * @param tagName * @return */ public StrElement selectFirst(String tagName) { List<StrElement> list = this.select(tagName); if (list.size() > 0) { return list.get(0); } return null; }
/** * 本元素的属性(不查找子元素). * * @param attrName * 属性名称 * @return 指定的属性不存在返回null,否则返回属性值 */ public String attr(String attrName) {
// 解析过,直接返回 if (attrMap != null) { return attrMap.get(attrName); }
// 解析 this.parseAllAttr();
// 返回 return attrMap.get(attrName); }
/** * 解析所有属性. */ private void parseAllAttr() {
if (attrMap != null) { return; }
attrMap = new HashMap<String, String>();
// <AAA xx="" yy=""><BBB><CCC zz=""/></BBB></AAA> int indexB = xml.indexOf(">"); char c = xml.charAt(indexB - 1); if (c == '/') { indexB = indexB - 1; } String self = xml.substring(0, indexB);
// split和replace别用,效率不行 int indexA = self.indexOf(" "); // 找空格 while (indexA != -1) { indexB = self.indexOf("\"", indexA + 1);
// 没有双引号了,就是没属性了,退出循环 if (indexB == -1) { break; }
// <AAA xx="123" yy=""> // 属性名称 String key = self.substring(indexA + 1, indexB - 1).trim();
// indexA = self.indexOf("\"", indexB + 1); // 查找关闭的双引号 String value = self.substring(indexB + 1, indexA).trim(); attrMap.put(key, value); } }
/** * 获取所有属性. * * @return */ public Map<String, String> getAttrMap() {
parseAllAttr();
return attrMap; }
public List<StrElement> children() {
List<StrElement> list = new ArrayList<StrElement>();
// <AAA xx="" yy=""><BBB><CCC zz=""/></BBB></AAA> int indexA = xml.indexOf(">");
// 查找"<" indexA = xml.indexOf("<", indexA); while (indexA != -1) {
// </AAA>自身的结束标签 char c = xml.charAt(indexA + 1); if (c == '/') { break; }
// 查找">" int indexB = xml.indexOf(">", indexA); c = xml.charAt(indexB - 1); if (c == '/') { // 如果是/>,那么说明是自关闭的tag String oneRow = xml.substring(indexA, indexB + 1); list.add(new StrElement(oneRow));
// 下一个 indexA = xml.indexOf("<", indexB + 1); continue; }
// 否则,查找结束Tag int indexB1 = xml.indexOf(" ", indexA); // 不一定有 int indexB2 = xml.indexOf(">", indexA); // 一定有 if (indexB1 == -1 || indexB1 > indexB2) { indexB = indexB2; } else { indexB = indexB1; } String endTagName = "</" + xml.substring(indexA + 1, indexB).trim() + ">";
// 截取一个 indexB = xml.indexOf(endTagName, indexA); indexB += endTagName.length(); String oneRow = xml.substring(indexA, indexB); list.add(new StrElement(oneRow));
// 下一个 indexA = xml.indexOf("<", indexB); // 不能+1了,indexB可能已经指向"<"了。 } return list; }
/** * 获取Tag名称. * * @return */ public String tagName() {
// <AAA>..或者<AAA xx="yy"> int indexB = 0; int indexB1 = xml.indexOf(" "); // 不一定有 int indexB2 = xml.indexOf(">"); // 一定有 if (indexB1 == -1 || indexB1 > indexB2) { indexB = indexB2; } else { indexB = indexB1; } return xml.substring(1, indexB).trim(); }
/** * 返回文本(直接返回的开始Tag和结束Tag之间的内容). * * @return */ public String text() {
// 查找">" int indexB = xml.indexOf(">"); char c = xml.charAt(indexB - 1); if (c == '/') { // 如果是/>,那么说明是自关闭的tag return ""; }
return xml.substring(indexB + 1, xml.lastIndexOf("</")).trim(); }
/** * 输出XML. * * @return */ public String toXML() { return xml; }
public static void main(String[] args) { String xml = "<OriginDestinationOption ElapsedTime=\"125\"> <FlightSegment DepartureDateTime=\"2017-12-12T08:50:00\" ArrivalDateTime=\"2017-12-12T11:55:00\" StopQuantity=\"0\" FlightNumber=\"896\" ResBookDesigCode=\"N\" ElapsedTime=\"125\"> <DepartureAirport LocationCode=\"PVG\" TerminalID=\"1\"/> <ArrivalAirport LocationCode=\"ICN\"/> <OperatingAirline Code=\"KE\" FlightNumber=\"896\"/> <Equipment AirEquipType=\"332\"/> <MarketingAirline Code=\"KE\"/> <MarriageGrp>O</MarriageGrp> <DepartureTimeZone GMTOffset=\"8\"/> <ArrivalTimeZone GMTOffset=\"9\"/> <TPA_Extensions> <eTicket Ind=\"true\"/> <Mileage Amount=\"506\"/> </TPA_Extensions> </FlightSegment> </OriginDestinationOption>"; StrElement ele = new StrElement(xml); System.out.println(ele.attr("ElapsedTime"));
List<StrElement> list = ele.select("FlightSegment"); Map<String, String> attrMap = list.get(0).getAttrMap(); for (Entry<String, String> entry : attrMap.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); }
// list = list.get(0).select("TPA_Extensions"); // attrMap = list.get(0).getAttrMap(); // for(Entry<String,String> entry:attrMap.entrySet()) { // System.out.println(entry.getKey() + ":" + entry.getValue()); // }
List<StrElement> children = list.get(0).children(); for (StrElement e : children) { System.out.println(e.toXML()); // System.out.println(e.tagName()); }
}
}
|