[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[整理]java用字符串的indexOf和substring来解析XML

上一篇:[备忘]xstream,xml转为bean时,跳过没写的属性
下一篇:[备忘]不要在linux上启用net.ipv4.tcp_tw_recycle参数【重要,否则会出现连接超时】

添加日期:2017/12/12 19:08:38 快速返回   返回列表 阅读2239次
访问量较大,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());
        }

    }

}



 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved