- 相關(guān)推薦
用Java如何處理XML數(shù)據(jù)
Java原生內(nèi)置的處理XML的技術(shù)基本有這么幾種:DOM,SAX,Stax,Jaxb.那么用Java我們要如何處理XML數(shù)據(jù),希望對大家有幫助!
DOM :Document Object Model 顧名思義就是在內(nèi)存中構(gòu)建樹形結(jié)構(gòu)。處理小的XML文件還算勉強(qiáng)應(yīng)付。如果文件比較大,他需要一次性裝載整個XML,你會忍不了他的速度,并且他會吃光你所有的內(nèi)存,最后程序會負(fù)分滾粗。
SAX:Simple API for XML Parsing 一般名字應(yīng)該是沒實現(xiàn)的愿望體現(xiàn)。比如一個人如果叫王金庫,那么可以肯定他絕對沒有金庫。這樣你應(yīng)該理解這個API為啥叫Simple了。這API是回調(diào)式的,也就是你寫的程序是被別人調(diào)戲用的。這API比DOM快點,而且是可以部分裝載XML,這樣你不用害怕OOME了。啥?你想寫XML?忘掉這個叫Simple的玩意兒吧。
Stax: Streaming API for XML 這個總算是靠點譜了。你寫的程序是主動式的訪問XML各個節(jié)點。流式訪問,不用擔(dān)心OOME,速度嘛算是原生態(tài)里面最好的了。而且讀寫都支持,你不用這個還用哪個啊?
給個Stax的代碼片段,算是參考吧:
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
xsr.nextTag(); // Advance to statements element
long i = 0;
String action = null;
while (xsr.hasNext()) {
if (xsr.next() == XMLStreamConstants.START_ELEMENT) {
if ("ContentItem".equals(xsr.getLocalName())) {
action = getAttributeValue(xsr, "action");
} else if ("Data".equals(xsr.getLocalName())) {
i ++;
}
}
}
JAXB:Java Architecture for XML Binding 這是一個很酷的API.想法就是把XML各種屬性定義映射到普通的Java Bean上。你無須關(guān)心解析反解析的細(xì)節(jié),只要用普通的Java Bean就完成和XML的交互了?墒窃趺礃(gòu)建一一映射的JavaBean呢?在已知XML的定義的情況下你可以用自帶的xjc 命令自動生成相對應(yīng)的JavaBean.如果你用Eclipse,有類似的插件幫你完成這步。具體可以google一下。然后你要做的就是僅僅是使用數(shù)據(jù)啦。簡單的令人發(fā)指:
JAXBContext jc = JAXBContext.newInstance("com.your.xml.datatype.bean"); // 先注冊你的JavaBean
// Create unmarshaller
Unmarshaller um = jc.createUnmarshaller();
// Unmarshal XML contents of the file myDoc.xml into your Java object
// instance
ObjectFactory objFac = new ObjectFactory(); // 生成Bean之后你會有這個工廠類的
objFac.createYourData(objFac.createYourDataType());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("your.xml")); // 你要怎么打開你的XML文件呢?
JAXBElement myJAXBObject = (JAXBElement) um.unmarshal(bis); // 讀取
YourDataType yourData = (YourDataType) myJAXBObject.getValue(); // 可以用啦
// 下面是寫XML的例子
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
File outfile = new File("yourOutput.xml");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outfile), 4096);
m.marshal(myJAXBObject, bos); // 一步寫入。 myJAXBObject 需要你自己構(gòu)建,你要存什么呢
try {
bos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
bos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
你也許意識到問題了:這一下子把XML Load到內(nèi)存里,你是不是瘋了?為了避免瘋掉,你可以用Satx啊,那玩意兒不是流式的么?給個栗子,讀取這樣的XML文件片段:
<OutXMLData>
<SubXMLItemType>
…
</SubXMLItemType>
<SubXMLItemType>
…
</SubXMLItemType>
<SubXMLItemType>
…
</SubXMLItemType>
…
</OutXMLData>
private static void readWriteWithStAXAndJAXB() throws FactoryConfigurationError, FileNotFoundException, XMLStreamException, UnsupportedEncodingException, JAXBException,
PropertyException {
// set up a StAX reader
XMLInputFactory xmlif = XMLInputFactory.newInstance();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("inputLarge.xml"));
XMLStreamReader xmlr = xmlif.createXMLStreamReader(bis);
File outfile = new File("output\outfile.xml");
OutputStreamWriter bos = new OutputStreamWriter(new FileOutputStream(outfile), "UTF-8");
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(bos);
xmlw.writeStartDocument("UTF-8", "1.0");
xmlw.writeStartElement("OutXMLData");
JAXBContext ucontext = JAXBContext.newInstance(SubXMLItemType.class);
Unmarshaller unmarshaller = ucontext.createUnmarshaller();
Marshaller marshaller = ucontext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
xmlr.nextTag();
xmlr.require(XMLStreamConstants.START_ELEMENT, null, "OutXMLData");
xmlr.nextTag();
int iCount = 0;
while (xmlr.getEventType() == XMLStreamConstants.START_ELEMENT) { // 按標(biāo)簽流式讀取
iCount++;
JAXBElement
marshaller.marshal(pt, xmlw); // 這步是分批流式寫入
xmlw.writeCharacters(" ");
if (xmlr.getEventType() == XMLStreamConstants.CHARACTERS) {
xmlr.next();
}
}
xmlw.flush();
xmlw.writeEndElement();
xmlw.writeEndDocument();
System.out.println("Entity Count is :" + iCount);
xmlr.close();
xmlw.close();
}
說完這么多,基本上用Java處理XML已經(jīng)不是難事了。不過,有時候你會有:給你蟹八件兒,你也無從下嘴的感受。比如,解析XML你可以掌控,隨便你用啥,可是你調(diào)用的下游程序接口卻需要另外一種格式的數(shù)據(jù)。比如,你用Stax解析XML,下游要DOM接口會不會令你抓狂起來?心里咒罵,倒霉玩意兒,你們還有沒有點上進(jìn)心?!最近我就遇到這事了,解析一個大的XML,下游要Sub的XML,或者叫XML片段,或者叫分割XML文件。好么,我把數(shù)據(jù)都拆成Java的Object,然后再給你拼成一個個小的XML文件發(fā)過去,喪心病狂么這不?!你如果真這么做了,就別往下看了,你會哭的!
Java 的XML包下面有個transform的子包,看看里面會有驚喜的?梢杂眠@個工具包幫你完成類似的轉(zhuǎn)換,比如Stax 和 Sax 或者Dom 互相的變換;蛘咦儞Q成Stream.
拿我這個分割XML的小栗子來說:
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml")); // 用Stax讀取XML
xsr.nextTag(); // Advance to statements element
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setParameter(OutputKeys.OMIT_XML_DECLARATION, "no");
t.setParameter(OutputKeys.STANDALONE, "yes");
long i = 0;
String action = null;
while (xsr.hasNext()) {
if (xsr.next() == XMLStreamConstants.START_ELEMENT) {
if ("ContentItem".equals(xsr.getLocalName())) {
action = getAttributeValue(xsr, "action");
} else if ("Data".equals(xsr.getLocalName())) {
File file = new File("out/" + action + i++ + ".xml");
t.transform(new StAXSource(xsr), new StreamResult(file)); // 流式變換,走你~
// DOMResult dr = new DOMResult(); // 如果你要Dom格式的,releaseMe
// t.transform(new StAXSource(xsr), dr);
}
}
}
知道最變態(tài)的是什么嗎?需要解析XML整個內(nèi)容到String里面,不單單是數(shù)據(jù),就是整個XML標(biāo)簽和數(shù)據(jù)。其實就是ouputStream轉(zhuǎn)String的過程:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
t.transform(new StAXSource(xsr), new StreamResult(baos));
String subXMLStr = baos.toString();
【用Java如何處理XML數(shù)據(jù)】相關(guān)文章:
關(guān)于XML技術(shù)在數(shù)據(jù)交換中的應(yīng)用03-29
Java中日期的處理方法03-09
如何編譯java程序03-05
如何讓JAVA代碼更高效03-20
java數(shù)據(jù)類型和運(yùn)算符03-06