如何读写 XML 文件?
Posted
技术标签:
【中文标题】如何读写 XML 文件?【英文标题】:How to read and write XML files? 【发布时间】:2017-01-12 15:02:27 【问题描述】:我必须读写XML 文件。使用 Java 读写 XML 文件最简单的方法是什么?
【问题讨论】:
通过StAX进行内存高效的部分xml解析:***.com/questions/52614082/… 【参考方案1】:这是一个快速的 DOM 示例,展示了如何使用其 dtd 读取和写入一个简单的 xml 文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE roles SYSTEM "roles.dtd">
<roles>
<role1>User</role1>
<role2>Author</role2>
<role3>Admin</role3>
<role4/>
</roles>
和 dtd:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT roles (role1,role2,role3,role4)>
<!ELEMENT role1 (#PCDATA)>
<!ELEMENT role2 (#PCDATA)>
<!ELEMENT role3 (#PCDATA)>
<!ELEMENT role4 (#PCDATA)>
首先导入这些:
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.w3c.dom.*;
以下是您需要的一些变量:
private String role1 = null;
private String role2 = null;
private String role3 = null;
private String role4 = null;
private ArrayList<String> rolev;
这是一个阅读器(字符串 xml 是您的 xml 文件的名称):
public boolean readXML(String xml)
rolev = new ArrayList<String>();
Document dom;
// Make an instance of the DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try
// use the factory to take an instance of the document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// parse using the builder to get the DOM mapping of the
// XML file
dom = db.parse(xml);
Element doc = dom.getDocumentElement();
role1 = getTextValue(role1, doc, "role1");
if (role1 != null)
if (!role1.isEmpty())
rolev.add(role1);
role2 = getTextValue(role2, doc, "role2");
if (role2 != null)
if (!role2.isEmpty())
rolev.add(role2);
role3 = getTextValue(role3, doc, "role3");
if (role3 != null)
if (!role3.isEmpty())
rolev.add(role3);
role4 = getTextValue(role4, doc, "role4");
if ( role4 != null)
if (!role4.isEmpty())
rolev.add(role4);
return true;
catch (ParserConfigurationException pce)
System.out.println(pce.getMessage());
catch (SAXException se)
System.out.println(se.getMessage());
catch (IOException ioe)
System.err.println(ioe.getMessage());
return false;
还有一位作家:
public void saveToXML(String xml)
Document dom;
Element e = null;
// instance of a DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try
// use factory to get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// create instance of DOM
dom = db.newDocument();
// create the root element
Element rootEle = dom.createElement("roles");
// create data elements and place them under root
e = dom.createElement("role1");
e.appendChild(dom.createTextNode(role1));
rootEle.appendChild(e);
e = dom.createElement("role2");
e.appendChild(dom.createTextNode(role2));
rootEle.appendChild(e);
e = dom.createElement("role3");
e.appendChild(dom.createTextNode(role3));
rootEle.appendChild(e);
e = dom.createElement("role4");
e.appendChild(dom.createTextNode(role4));
rootEle.appendChild(e);
dom.appendChild(rootEle);
try
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.setOutputProperty(OutputKeys.METHOD, "xml");
tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "roles.dtd");
tr.setOutputProperty("http://xml.apache.org/xsltindent-amount", "4");
// send DOM to file
tr.transform(new DOMSource(dom),
new StreamResult(new FileOutputStream(xml)));
catch (TransformerException te)
System.out.println(te.getMessage());
catch (IOException ioe)
System.out.println(ioe.getMessage());
catch (ParserConfigurationException pce)
System.out.println("UsersXML: Error trying to instantiate DocumentBuilder " + pce);
getTextValue 在这里:
private String getTextValue(String def, Element doc, String tag)
String value = def;
NodeList nl;
nl = doc.getElementsByTagName(tag);
if (nl.getLength() > 0 && nl.item(0).hasChildNodes())
value = nl.item(0).getFirstChild().getNodeValue();
return value;
添加一些访问器和修改器就完成了!
【讨论】:
这个工作需要 dtd 文件还是我们可以在没有 dtd 的情况下读取 xml?如果需要 dtd,我们可以轻松地从 xml 生成 dtd,而不是自己输入吗? 您可以不使用 dtd 文件。确保您还从 xml 文件中删除了对它的引用:。您可以找到免费的 dtd 生成器应用程序或使用在线服务。他们会生成一个“足够好”的 dtd 文件。通常你需要稍微修改一下。 很好的例子!我对 getTextValue() 函数有一个小问题,如果节点为空,它应该返回一个长度为零的字符串而不是 null。我必须添加“if(value==null) value = "";"在“返回值”之前,否则在写入 XML 字符串时会崩溃。 @CostisAivalis 你能告诉我如何在 Batik here 中解析和保存 svg。我在区分 XML 和 Batik 的工作方式时遇到问题。【参考方案2】:上面的答案只处理 DOM 解析器(通常读取内存中的整个文件并解析它,对于大文件来说是个问题),您可以使用使用更少内存且速度更快的 SAX 解析器(无论如何取决于您的代码)。
SAX 解析器在找到元素的开头、元素的结尾、属性、元素之间的文本等时回调一些函数,这样它就可以解析文档,同时你 得到你需要的东西。
一些示例代码:
http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
【讨论】:
【参考方案3】:使用 JAXB(用于 XML 绑定的 Java 架构)编写 XML:
http://www.mkyong.com/java/jaxb-hello-world-example/
package com.mkyong.core;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer
String name;
int age;
int id;
public String getName()
return name;
@XmlElement
public void setName(String name)
this.name = name;
public int getAge()
return age;
@XmlElement
public void setAge(int age)
this.age = age;
public int getId()
return id;
@XmlAttribute
public void setId(int id)
this.id = id;
package com.mkyong.core;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JAXBExample
public static void main(String[] args)
Customer customer = new Customer();
customer.setId(100);
customer.setName("mkyong");
customer.setAge(29);
try
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(customer, file);
jaxbMarshaller.marshal(customer, System.out);
catch (JAXBException e)
e.printStackTrace();
【讨论】:
【参考方案4】:答案仅涵盖 DOM / SAX 和 JAXB 示例的复制粘贴实现。
但是,缺少使用 XML 的一大方面。在许多项目/程序中,需要存储/检索一些基本数据结构。您的程序已经为您的漂亮而闪亮的业务对象/数据结构提供了一个类,您只需要一种舒适的方式将这些数据转换为 XML 结构,以便您可以对它做更多的魔法(存储、加载、发送、使用 XSLT 操作) .
这就是 XStream 的亮点所在。您只需对保存数据的类进行注释,或者如果您不想更改这些类,则配置一个 XStream 实例以进行编组(对象 -> xml)或解组(xml -> 对象)。
XStream 在内部使用反射、标准 Java 对象序列化的 readObject 和 readResolve 方法。
你会得到一个很好的快速教程here:
为了简要概述它的工作原理,我还提供了一些编组和解组数据结构的示例代码。
编组/解组都发生在main
方法中,其余的只是生成一些测试对象并向它们填充一些数据的代码。
配置xStream
实例非常简单,编组/解编组只需一行代码。
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.XStream;
public class XStreamIsGreat
public static void main(String[] args)
XStream xStream = new XStream();
xStream.alias("good", Good.class);
xStream.alias("pRoDuCeR", Producer.class);
xStream.alias("customer", Customer.class);
Producer a = new Producer("Apple");
Producer s = new Producer("Samsung");
Customer c = new Customer("Someone").add(new Good("S4", 10, new BigDecimal(600), s))
.add(new Good("S4 mini", 5, new BigDecimal(450), s)).add(new Good("I5S", 3, new BigDecimal(875), a));
String xml = xStream.toXML(c); // objects -> xml
System.out.println("Marshalled:\n" + xml);
Customer unmarshalledCustomer = (Customer)xStream.fromXML(xml); // xml -> objects
static class Good
Producer producer;
String name;
int quantity;
BigDecimal price;
Good(String name, int quantity, BigDecimal price, Producer p)
this.producer = p;
this.name = name;
this.quantity = quantity;
this.price = price;
static class Producer
String name;
public Producer(String name)
this.name = name;
static class Customer
String name;
public Customer(String name)
this.name = name;
List<Good> stock = new ArrayList<Good>();
Customer add(Good g)
stock.add(g);
return this;
【讨论】:
【参考方案5】:好的,答案列表中已经有了 DOM、JaxB 和 XStream,还有完全不同的方式来读写 XML:Data projection您可以使用提供的库来解耦 XML 结构和 Java 结构作为 Java 接口的 XML 数据的可读写视图。来自tutorials:
给定一些真实世界的 XML:
<weatherdata>
<weather
...
degreetype="F"
lat="50.5520210266113" lon="6.24060010910034"
searchlocation="Monschau, Stadt Aachen, NW, Germany"
... >
<current ... skytext="Clear" temperature="46"/>
</weather>
</weatherdata>
使用数据投影可以定义一个投影接口:
public interface WeatherData
@XBRead("/weatherdata/weather/@searchlocation")
String getLocation();
@XBRead("/weatherdata/weather/current/@temperature")
int getTemperature();
@XBRead("/weatherdata/weather/@degreetype")
String getDegreeType();
@XBRead("/weatherdata/weather/current/@skytext")
String getSkytext();
/**
* This would be our "sub projection". A structure grouping two attribute
* values in one object.
*/
interface Coordinates
@XBRead("@lon")
double getLongitude();
@XBRead("@lat")
double getLatitude();
@XBRead("/weatherdata/weather")
Coordinates getCoordinates();
并且像 POJO 一样使用这个接口的实例:
private void printWeatherData(String location) throws IOException
final String BaseURL = "http://weather.service.msn.com/find.aspx?outputview=search&weasearchstr=";
// We let the projector fetch the data for us
WeatherData weatherData = new XBProjector().io().url(BaseURL + location).read(WeatherData.class);
// Print some values
System.out.println("The weather in " + weatherData.getLocation() + ":");
System.out.println(weatherData.getSkytext());
System.out.println("Temperature: " + weatherData.getTemperature() + "°"
+ weatherData.getDegreeType());
// Access our sub projection
Coordinates coordinates = weatherData.getCoordinates();
System.out.println("The place is located at " + coordinates.getLatitude() + ","
+ coordinates.getLongitude());
这甚至适用于创建 XML,XPath 表达式是可写的。
【讨论】:
【参考方案6】:SAX
解析器与DOM
解析器的工作方式不同,它既不会将任何XML
文档加载到内存中,也不会创建XML
文档的任何对象表示。相反,SAX
解析器使用回调函数org.xml.sax.helpers.DefaultHandler
通知客户端XML
文档结构。
SAX
解析器比DOM
解析器更快并且使用更少的内存。
请参阅以下SAX
回调方法:
startDocument()
和 endDocument()
– 在 XML 文档的开头和结尾调用的方法。
startElement()
和 endElement()
– 在文档元素的开头和结尾调用的方法。
characters()
– 使用 XML 文档元素的开始和结束标记之间的文本内容调用的方法。
-
XML 文件
创建一个简单的 XML 文件。
<?xml version="1.0"?>
<company>
<staff>
<firstname>yong</firstname>
<lastname>mook kim</lastname>
<nickname>mkyong</nickname>
<salary>100000</salary>
</staff>
<staff>
<firstname>low</firstname>
<lastname>yin fong</lastname>
<nickname>fong fong</nickname>
<salary>200000</salary>
</staff>
</company>
-
XML 解析器:
Java 文件 使用 SAX 解析器解析 XML 文件。
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ReadXMLFile
public static void main(String argv[])
try
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler()
boolean bfname = false;
boolean blname = false;
boolean bnname = false;
boolean bsalary = false;
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException
System.out.println("Start Element :" + qName);
if (qName.equalsIgnoreCase("FIRSTNAME"))
bfname = true;
if (qName.equalsIgnoreCase("LASTNAME"))
blname = true;
if (qName.equalsIgnoreCase("NICKNAME"))
bnname = true;
if (qName.equalsIgnoreCase("SALARY"))
bsalary = true;
public void endElement(String uri, String localName,
String qName) throws SAXException
System.out.println("End Element :" + qName);
public void characters(char ch[], int start, int length) throws SAXException
if (bfname)
System.out.println("First Name : " + new String(ch, start, length));
bfname = false;
if (blname)
System.out.println("Last Name : " + new String(ch, start, length));
blname = false;
if (bnname)
System.out.println("Nick Name : " + new String(ch, start, length));
bnname = false;
if (bsalary)
System.out.println("Salary : " + new String(ch, start, length));
bsalary = false;
;
saxParser.parse("c:\\file.xml", handler);
catch (Exception e)
e.printStackTrace();
结果
起始元素:公司 开始元素:staff 开始元素:名字 名字 : yong 结束元素:名字 起始元素:姓氏 姓 : mook kim 结束元素:姓氏 开始元素:昵称 昵称:mkyong 结束元素:昵称 等等……
来源(MyKong) - http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
【讨论】:
以上是关于如何读写 XML 文件?的主要内容,如果未能解决你的问题,请参考以下文章