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