簡體   English   中英

Java:使用嵌套節點解析XML時遇到麻煩

[英]Java: Having trouble parsing XML with nested nodes

我有一個類似這樣的XML文件

<album>
    <title> Sample Album </title>
    <year> 2014 </year>
    <musicalStyle> Waltz </musicalStyle>
        <song> Track 1 </song>
        <song> Track 2 </song>
        <song> Track 3 </song>
        <song> Track 4 </song>
        <song> Track 5 </song>
        <song> Track 6 </song>
        <song> Track 7 </song>
</album>

我可以按照一個教程來解析歌曲,但現在我受困於嵌套節點。 Song.XMLtitleStartTag = <title> ,結束標記為</title>

public static SongList parseFromFile(File inputFile){
    System.out.println("Parse File Data:");     
    if(inputFile == null) return null;      
    SongList theSongs  = new SongList();        
    BufferedReader inputFileReader;

    String inputLine; //current input line
    try{
           inputFileReader= new BufferedReader(new FileReader(inputFile));

           while((inputLine = inputFileReader.readLine()) != null){
               if(inputLine.trim().startsWith(Song.XMLtitleStartTag) && 
                   inputLine.endsWith(Song.XMLtitleEndTag)){

                   String titleString = inputLine.substring(Song.XMLtitleStartTag.length()+1, 
                           inputLine.length()- Song.XMLtitleEndTag.length()).trim();

                   if(titleString != null && titleString.length() > 0)
                       theSongs.add(new Song(titleString))              
               }
           } 

我知道解析XML有不同的方法,我想知道是應該堅持使用我所使用的方法並以此為基礎,還是應該嘗試一種更簡單的方法。

還想知道是否可以通過解析專輯信息的其余部分獲得一個指針

簡短的答案是,是的,您應該放棄當前的方法並尋求其他方法。 開發人員已經花費了數百個小時來制作能夠以標准化方式解析XML文件的庫。

有許多庫可用於解析XML。

您可以先看看內置的API,即用於XML處理的Java API(JAXP)

通常,它可以歸結為兩種方法。

SAX或DOM。

SAX基本上是解析后的XML的內聯處理。 這意味着,在處理XML文檔時,將有機會處理該解析。 這對於大型文檔以及僅需要線性訪問內容的情況很有用。

DOM(或文檔對象模型)生成XML的模型,您可以隨意處理該模型。 它更適合於較小的XML文檔,因為通常會將整個模型讀入內存中,並且當您想以非線性方式與文檔進行交互時(例如搜索...)。

以下是在DOM中加載XML文檔的簡單片段...

try {
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    try {
        Document doc = builder.parse(new File("Album.xml"));
    } catch (SAXException | IOException ex) {
        ex.printStackTrace();
    }
} catch (ParserConfigurationException exp) {
    exp.printStackTrace();
}

擁有Document ,您就可以按照自己認為合適的任何方式對其進行處理。 在我看來,我們來看看XPath ,它是XML的查詢API

例如...

import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class SongList {

    public static void main(String[] args) {
        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            try {
                Document doc = builder.parse(new File("Album.xml"));

                XPathFactory xPathFactory = XPathFactory.newInstance();
                XPath xPath = xPathFactory.newXPath();

                // Find all album tabs starting at the root level
                XPathExpression xExpress = xPath.compile("/album");
                NodeList nl = (NodeList)xExpress.evaluate(doc.getDocumentElement(), XPathConstants.NODESET);
                for (int index = 0; index < nl.getLength(); index++) {

                    Node albumNode = nl.item(index);
                    // Find the title node that is a child of the albumNode
                    Node titleNode = (Node) xPath.compile("title").evaluate(albumNode, XPathConstants.NODE);
                    System.out.println(titleNode.getTextContent());

                }

                // Find all albums whose title is equal to " Sample Album "
                xExpress = xPath.compile("/album[title=' Sample Album ']");
                nl = (NodeList)xExpress.evaluate(doc.getDocumentElement(), XPathConstants.NODESET);
                for (int index = 0; index < nl.getLength(); index++) {

                    Node albumNode = nl.item(index);
                    Node titleNode = (Node) xPath.compile("title").evaluate(albumNode, XPathConstants.NODE);
                    System.out.println(titleNode.getTextContent());

                }

            } catch (SAXException | IOException | XPathExpressionException ex) {
                ex.printStackTrace();
            }
        } catch (ParserConfigurationException exp) {
            exp.printStackTrace();
        }
    }

}

也許您可以嘗試類似的方法:

import java.io.File;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Test {

    public static final class Album {

        public final String title;
        public final String year;
        public final String style;

        public final List<Song> songs;

        Album(final String title, final String year, final String style){
            this.title = title;
            this.year = year;
            this.style = style;

            songs = new LinkedList<>();
        }
    }

    public static final class Song {

        public final Album album;
        public final String name;

        Song(final Album album, final String name){
            this.album = album;
            this.name = name;
        }
    }

    public static List<Album> getAlbums(final File xml) throws Exception {
        final List<Album> albums = new LinkedList<>();
        final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xml);
        doc.getDocumentElement().normalize();
        final NodeList list = doc.getElementsByTagName("album");
        for(int i = 0; i < list.getLength(); i++){
            final Node node = list.item(i);
            if(node.getNodeType() != Node.ELEMENT_NODE)
                continue;
            final Element e = (Element) node;
            final NodeList children = e.getChildNodes();
            final Album album = new Album(children.item(0).getNodeValue(), children.item(1).getNodeValue(), children.item(2).getNodeValue());
            final NodeList songs = e.getElementsByTagName("song");
            for(int j = 0; j < songs.getLength(); j++)
                album.songs.add(new Song(album, songs.item(j).getNodeValue()));
            albums.add(album);
        }
        return albums;
    }
}

正確解析XML需要比您在此處使用的例程更加靈活(復雜)的機制。 您最好使用現有的解析器。

如果您真的想編寫自己的代碼,則此代碼不是可行方法的基礎。 請記住,XML不是基於行的,並且沒有要求在同一行上包含相關標簽。 這使得逐行解析文件成為一種困難且尷尬的入門方式,並且嘗試通過一次模式匹配一​​行來識別實體只是一種破爛的技術(任何實體可能總是跨越一行而已)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM