【问题标题】:How to read and write XML files?如何读写 XML 文件?
【发布时间】:2017-01-12 15:02:27
【问题描述】:

我必须读写XML 文件。使用 Java 读写 XML 文件最简单的方法是什么?

【问题讨论】:

标签: java xml xml-parsing


【解决方案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/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;
}

添加一些访问器和修改器就完成了!

【讨论】:

  • 这个工作需要 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 文档元素的开始和结束标记之间的文本内容调用的方法。

          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>
          
          1. 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/

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-09-21
            • 2010-11-05
            • 2012-03-04
            • 1970-01-01
            相关资源
            最近更新 更多