我需要解析一个XML流.因为我只需要做一次并构建我的java对象,所以SAX看起来是自然的选择.我正在扩展DefaultHandler并实现startElement,endElement和characters方法,在我的类中有成员保存当前读取值(在characters方法中).
我做我需要的东西没有问题,但我的代码变得非常复杂,我确信没有理由这样做,我可以做不同的事情.我的XML结构是这样的:
<players>
<player>
<id></id>
<name></name>
<teams total="2">
<team>
<id></id>
<name></name>
<start-date>
<year>2009</year>
<month>9</month>
</start-date>
<is-current>true</is-current>
</team>
<team>
<id></id>
<name></name>
<start-date>
<year>2007</year>
<month>11</month>
</start-date>
<end-date>
<year>2009</year>
<month>7</month>
</end-date>
</team>
</teams>
</player>
</players>
Run Code Online (Sandbox Code Playgroud)
当我意识到在文件的几个区域中使用相同的标记名称时,我的问题就出现了.例如,玩家和团队都存在id和name.我想创建我的java类Player和Team的实例.在解析时,我保留了布尔标志,告诉我我是否在团队部分,以便在endElement中我知道该名称是团队的名称,而不是玩家的名字等等.
这是我的代码的样子:
public class MyParser extends DefaultHandler {
private String currentValue;
private boolean inTeamsSection = false;
private Player player;
private Team team;
private List<Team> teams;
public void characters(char[] ch, int start, int length) throws SAXException {
currentValue = new String(ch, start, length);
}
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
if(name.equals("player")){
player = new Player();
}
if (name.equals("teams")) {
inTeamsSection = true;
teams = new ArrayList<Team>();
}
if (name.equals("team")){
team = new Team();
}
}
public void endElement(String uri, String localName, String name) throws SAXException {
if (name.equals("id")) {
if(inTeamsSection){
team.setId(currentValue);
}
else{
player.setId(currentValue);
}
}
if (name.equals("name")){
if(inTeamsSection){
team.setName(currentValue);
}
else{
player.setName(currentValue);
}
}
if (name.equals("team")){
teams.add(team);
}
if (name.equals("teams")){
player.setTeams(teams);
inTeamsSection = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
因为在我的真实场景中,除了团队之外我还有更多的节点,并且这些节点也有像name和id这样的标签,我发现自己弄乱了几个类似于inTeamsSection的布尔值,而且我的endElement方法变得冗长而且复杂很多条件.
我该怎么办?我怎么知道名称标签属于什么?
谢谢!
Jör*_*ann 23
编写SAX解析器时有一个巧妙的技巧:允许ContentHandler在解析时更改
XMLReader.这允许将不同元素的解析逻辑分成多个类,这使得解析更加模块化和可重用.当一个处理程序看到其结束元素时,它会切换回其父元素.您实施的处理程序数量将留给您.代码如下所示:
public class RootHandler extends DefaultHandler {
private XMLReader reader;
private List<Team> teams;
public RootHandler(XMLReader reader) {
this.reader = reader;
this.teams = new LinkedList<Team>();
}
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
if (name.equals("team")) {
// Switch handler to parse the team element
reader.setContentHandler(new TeamHandler(reader, this));
}
}
}
public class TeamHandler extends DefaultHandler {
private XMLReader reader;
private RootHandler parent;
private Team team;
private StringBuilder content;
public TeamHandler(XMLReader reader, RootHandler parent) {
this.reader = reader;
this.parent = parent;
this.content = new StringBuilder();
this.team = new Team();
}
// characters can be called multiple times per element so aggregate the content in a StringBuilder
public void characters(char[] ch, int start, int length) throws SAXException {
content.append(ch, start, length);
}
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
content.setLength(0);
}
public void endElement(String uri, String localName, String name) throws SAXException {
if (name.equals("name")) {
team.setName(content.toString());
} else if (name.equals("team")) {
parent.addTeam(team);
// Switch handler back to our parent
reader.setContentHandler(parent);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10774 次 |
| 最近记录: |