[英]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.