Как читать и писать xml-файлы?


6 65

6 ответов:

вот быстрый пример DOM, который показывает, как читать и писать простой xml-файл с его dtd:

<?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;
}

добавить несколько аксессоров и мутаторов и вы закончили!

приведенный выше ответ касается только парсера DOM (который обычно читает весь файл в памяти и анализирует его, что для большого файла является проблемой), вы можете использовать парсер SAX, который использует меньше памяти и быстрее (в любом случае, это зависит от вашего кода).

SAX parser вызывает некоторые функции, когда он находит начало элемента, конец элемента, атрибут, текст между элементами и т. д., Поэтому он может анализировать документ и в то же время вы сделать то, что вам нужно.

пример код:

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

написание XML с помощью JAXB (Java Architecture for XML Binding):

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

    }
}

ответы охватывают только DOM / SAX и реализацию copy paste примера JAXB.

однако, одна большая область, когда вы используете XML отсутствует. Во многих проектах / программах необходимо хранить / извлекать некоторые базовые структуры данных. В вашей программе уже есть классы для ваших красивых и блестящих бизнес-объектов / структур данных, вам просто нужен удобный способ конвертировать эти данные в структуру XML, чтобы вы могли делать больше магии на нем (хранить, загружать, отправлять, манипулировать язык XSLT.)

вот где сияет XStream. Вы просто аннотируете классы, содержащие ваши данные, или, если вы не хотите изменять эти классы, вы настраиваете экземпляр XStream для маршалинга (objects -> xml) или unmarshalling (xml -> objects).

внутренне XStream использует отражение, readObject и readResolve методы стандартной сериализации объектов Java.

вы получили хороший и быстрый учебник здесь:

кратко обзор того, как это работает, я также предоставляю некоторый пример кода, который маршалирует и размечает структуру данных. Маршалинг / unmarshalling происходит все в 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;
    }
  }
}

хорошо, уже имея DOM, JaxB и XStream в списке ответов, есть еще совершенно другой способ чтения и записи XML:проекции данных вы можете отделить структуру XML и структуру Java с помощью библиотеки, которая предоставляет читаемые и записываемые представления для XML-данных в качестве интерфейсов Java. Из уроки:

учитывая некоторые реальные 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();
}

и использовать экземпляры этого интерфейса так же, как POJOs:

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 могут быть доступны для записи.

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 parser:

файл 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();
        }

    }

}

результат

Start Element: company
Стартовый элемент: staff
Начальный элемент :имя
Имя : Ен
Конечный элемент :имя
Начальный элемент: фамилия
Фамилия: мук Ким
Конечный элемент :фамилия
Начальный элемент: ник
Ник : mkyong
Конечный элемент: ник
и так далее...

Источник (MyKong) - http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/