salesforce 零基础学习(三十二)通过Streams和DOM方式读写XML

有的时候我们需要对XML进行读写操作,常用的XML操作主要有Streams和DOM方式。

一.Streams方式

Streams常用到的类主要有两个XmlStreamReader 以及XmlStreamWriter。

XmlStreamReader:此种读取方式的读的特点为从上而下读,下图是根据reader的EventType自上而下的运行步骤。

我们将此xml读取后封装到一个Goods的List中,Goods包括item,name以及type属性,代码如下:

/*
* 假定目前XML数据样式为:
*<?xml version="1.0"?>
*<goodsList>
*    <goods item="1">
*        <name>华为手机</name>
*        <type>华为</type>
*    </goods>
*    <goods item="2">
*        <name>小米手机</name>
*        <type>小米</type>
*    </goods>
*</goodsList>
* 需要将xml解析成Goods的一个List
*/
public class XmlReaderController {
    public class Goods {
        public String item{get;set;}
        public String name{get;set;}
        public String type{get;set;}
    }
    
    public List<Goods> getGoodsListByXmlFile(String goodsXml) {
        XmlStreamReader reader = new XmlStreamReader(goodsXml);
        Boolean flagXmlEnd = true;
        List<Goods> goodsList = new List<Goods>();
        while(flagXmlEnd) {
            Goods tempGoods;
            if(reader.getEventType() == XmlTag.START_ELEMENT) {
                if(reader.getLocalName().equalsIgnoreCase('goods')) {
                    tempGoods = getGoods(reader);
                }
            }
            
            if(reader.hasNext()) {
                reader.next();
            } else {
                flagXmlEnd = false;
                break;
            }
            if(tempGoods != null) {
                goodsList.add(tempGoods);
            }
        }
        return goodsList;
    }
    
    
    Goods getGoods(XmlStreamReader reader) {
        Goods tempGoods = new Goods();
        tempGoods.item = reader.getAttributeValue(null,'item');
        Boolean flagIsLoop = true;
        while(flagIsLoop) {
            if(reader.hasNext()) {
                reader.next();
                if(reader.getEventType() == XmlTag.START_ELEMENT) {
                    if(reader.getLocalName().equalsIgnoreCase('name')) {
                        reader.next();
                        tempGoods.name = reader.getText();
                    } else if(reader.getLocalName().equalsIgnoreCase('type')) {
                        reader.next();
                        tempGoods.type = reader.getText();
                    }
                }
                if(reader.getEventType() == XmlTag.END_ELEMENT && reader.getLocalName().equalsIgnoreCase('goods')) {
                    flagIsLoop = false;
                    break;
                }
            } else {
                flagIsLoop = false;
                break;
            }
        }
        return tempGoods;
    }
}

在匿名块测试方法:

String goodsXml = '<?xml version="1.0"?>' +
        '<goodsList>' +
            '<goods item="1">' +
                '<name>华为手机</name>' +
                '<type>华为</type>' +
            '</goods>' +
            '<goods item="2">' +
                '<name>小米手机</name>' +
                '<type>小米</type>' +
            '</goods>' +
        '</goodsList>';
List<XmlReaderController.Goods> goodsList = new XmlReaderController().getGoodsListByXmlFile(goodsXml);
System.debug(JSON.serialize(goodsList));

显示结果:

[
{
"type":"华为",
"name":"华为手机",
"item":"1"
},
{
"type":"小米",
"name":"小米手机",
"item":"2"
}

 XmlStreamWriter:处理过程同XmlStreamReader,需要从上到下进行写入,例如如果写出上述的xml文件,需要先startDocument,然后再startElement.....要注意每个start需要对应相应的end方法。

public class XmlWriterController {
    
    public static void writeXml() {
        XmlStreamWriter writer = new XmlStreamWriter();
        writer.writeStartDocument('utf-8','1.0');
        writer.writeComment('goodsList start here');
        writer.writeStartElement('','goodsList','http://www.goods.com');
        writer.writeNamespace('', 'http://www.goods.com'); 
        writer.writeStartElement(null,'goods',null);
        writer.writeAttribute(null,null,'item','1');
        writer.writeStartElement(null,'name',null);
        writer.writeCharacters('华为手机');
        writer.writeEndElement();
        writer.writeStartElement(null,'type',null);
        writer.writeCharacters('华为');
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeStartElement(null,'goods',null);
        writer.writeAttribute(null,null,'item','2');
        writer.writeStartElement(null,'name',null);
        writer.writeCharacters('小米手机');
        writer.writeEndElement();
        writer.writeStartElement(null,'type',null);
        writer.writeCharacters('小米');
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndDocument();
        system.debug(writer.getXmlString());
    }
}

 二.Dom解析

dom解析原理同java对于dom解析相同,这里,goodsList作为根节点,goodsList的子节点有goods1,goods.他们分别有属性item1和item2,goods1以及goods2又分别有相应的子节点。

通过dom方式将上述xml解析成Goods的List。

public class DomXmlController {
    public class Goods {
        String item{get;set;}
        String name{get;set;}
        String type{get;set;}
    }
    public List<Goods> getGoodsViaXmlDom(String xmlString) {
        Dom.Document document = new Dom.Document();
        document.load(xmlString);
        Dom.XmlNode rootElement = document.getRootElement();
        List<Goods> goodsList = new List<Goods>();
        for(Dom.XmlNode node : rootElement.getChildElements()) {
            if(node.getName().equalsIgnoreCase('goods')) {
                Goods tempGoods = new Goods();
                tempGoods = getGoodsNameAndType(node);
                tempGoods.item = node.getAttribute('item',null);
                goodsList.add(tempGoods);
            }
        }
        
        return goodsList;
    }
    
    Goods getGoodsNameAndType(Dom.XmlNode parentNode) {
        transient Goods tempGoods = new Goods();
        for(Dom.XmlNode node : parentNode.getChildElements()) {
            if(node.getName().equalsIgnoreCase('name')) {
                tempGoods.name = node.getText();
            } else if(node.getName().equalsIgnoreCase('type')) {
                tempGoods.type = node.getText();
            }
        }
        return tempGoods;
    }
}

匿名块测试内容如下:

String goodsXml = '<?xml version="1.0"?>' +
        '<goodsList>' +
            '<goods item="1">' +
                '<name>华为手机</name>' +
                '<type>华为</type>' +
            '</goods>' +
            '<goods item="2">' +
                '<name>小米手机</name>' +
                '<type>小米</type>' +
            '</goods>' +
            
        '</goodsList>';
System.debug(JSON.serialize(new DomXmlController().getGoodsViaXmlDom(goodsXml)));

显示结果:

总结:apex对于xml操作和java很类似,或者说大部分都是从java过来的,如果java解析xml很娴熟情况下,使用apex解析xml只需要看看方法就OK了。本篇只是描述最简单的xml操作,篇中好多方法没有使用到,有兴趣的或者想深入的可以自己看一下相关的api。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏恰同学骚年

[转] Agile Software Development 敏捷软件开发

  敏捷开发是一种软件开发方法,基于迭代和增量开发,通过自组织,跨团队,沟通协作完成开发工作。

722
来自专栏小樱的经验随笔

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b。 mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作...

32011
来自专栏漫漫全栈路

HTML页面中的lang属性

最近想做点小项目,好久没写前端了,打开VScode,输了个HTML,突然忘记了中文的lang标识是什么了,只是隐约记得是zh,然而科普之后才知道,14年学习的...

3714
来自专栏铭毅天下

Elasticsearch实战 | match_phrase搜不出来,怎么办?

? 1、问题抛出 某个词组在Elasitcsearch中的某个document中存在,就一定通过某种匹配方式把它搜出来。 举例: title=公路局正在治理...

4217
来自专栏后端技术探索

算法分析:算命测人品等程序的实现

朋友圈中常常被一些测人品或者测星座匹配的分享连接所刷屏,究其核心实现,其实都是相似的算法,今天周末,闲来无事,本猿把曾经帮别人做的一个算命公众号拿出来剖析一番。...

572
来自专栏WOLFRAM

九宫格数独游戏

1548
来自专栏SAP梦心的SAP分享

【SAP业务模式】之ICS(六):发票输出类型

      这篇开始主要讲述发票输出类型:       首先我们新建一个发票类型,用于公司间的发票MIV,而标准的发票类型还是F2保持不变:       一、新...

1869
来自专栏数据结构与算法

06:寻宝

06:寻宝 总时间限制: 2000ms 内存限制: 65536kB描述 传说很遥远的藏宝楼顶层藏着诱人的宝藏。小明历尽千辛万苦终于找到传说中的这个藏 宝楼,...

4177
来自专栏java工会

猿诗·用java随机生成一首诗

1833
来自专栏desperate633

[编程题] 赶去公司代码

终于到周末啦!小易走在市区的街道上准备找朋友聚会,突然服务器发来警报,小易需要立即回公司修复这个紧急bug。假设市区是一个无限大的区域,每条街道假设坐标是(X,...

552

扫码关注云+社区