2011-09-10 196 views

回答

116

这里是一个快速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.*; 

以下是您需要的几个变量:

这里是一个读者(字符串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/xslt}indent-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; 
} 

添加一些accessor和mutators,你就完成了!

+5

是工作需要这个DTD文件,或者我们可以读取没有dtd的xml?如果需要dtd,我们可以轻松地从xml生成一个dtd,而不是自己输入它。 – 2014-10-29 21:38:18

+3

你可以离开dtd文件。确保您还从xml文件中消除对它的引用:<!DOCTYPE roles SYSTEM“roles.dtd”>。您可以找到免费的dtd生成器应用程序或使用在线服务。他们生成一个“足够好”的dtd文件来开始。通常你将不得不修改它一点。 –

+1

感谢您的回复。 :) – 2014-10-30 13:43:47

10

上面的答案只涉及DOM解析器(通常读取内存中的整个文件并解析它,对于大文件来说是一个问题),您可以使用SAX解析器,该解析器使用更少的内存并且速度更快这取决于你的代码)。

SAX解析器回调一些函数,当它找到元素的开始,元素的结尾,属性,元素之间的文本等,所以它可以解析文档,同时你得到你需要的东西。

一些示例代码:

http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

8

使用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(); 
      } 

    } 
} 
3

的答案只包括DOM/SAX和复制一个JAXB实例的粘贴实现。

但是,当您使用XML时,一个大的领域就是缺失。在许多项目/程序中,需要存储/检索一些基本的数据结构。你的程序已经有了一个适合你的漂亮而闪亮的业务对象/数据结构的类,你只需要一个舒适的方式将这些数据转换为XML结构,这样你就可以做更多的魔术(存储,加载,发送和使用XSLT) 。

这是XStream的光芒。您只需注解持有数据的类,或者如果您不想更改这些类,则可以配置用于编组(对象 - > xml)或解组(xml - >对象)的XStream实例。

内部XStream使用反射,标准Java对象序列化的readObject和readResolve方法。

你得到一个很好的和快速的教程here

要给它是如何工作的一个简短概述,我还提供了Marshalls和一个解组数据结构的一些示例代码。 编组/解组发生在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; 
    } 
    } 
} 
1

好了,已经有DOM,JAXB及XStream在答案的列表,还有读写XML完全不同的方式:Data projection您可以通过使用库分离的XML结构和Java结构它为XML数据提供了可读写视图作为Java接口。从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表达式可以WRI表。

0

SAX解析器与DOM解析器的工作方式不同,既不会将任何XML文档加载到内存中,也不会创建任何XML文档的对象表示形式。相反,SAX解析器使用回调函数(org.xml.sax.helpers.DefaultHandler)来通知客户端XML文档结构。

SAX解析器比DOM解析器速度更快,占用的内存也更少。 请参阅以下SAX回调方法:

startDocument()and endDocument() - 在XML文档的开始和结束处调用的方法。 startElement()和endElement() - 在文档元素的开始和结束处调用的方法。 characters() - 使用XML文档元素的开始标记和结束标记之间的文本内容调用的方法。 1. 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> 
  • 爪哇文件 使用SAX解析器来解析XML文件。
  • 进口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(); 
    } 
    
    
        } 
    
    } 
    

    结果

    开始元素:公司
    开始元素:员工
    开始元素:名字
    名字:勇
    结束元素:名字
    开始元素:名字
    姓:mook kim
    结束语元:姓氏
    开始元素:昵称
    昵称:mkyong
    结束元素:昵称
    等等...

    源(MyKong) - http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/