javasax解析

javasax解析,java,xml,sax,Java,Xml,Sax,我需要解析一个XML流。因为我只需要做一次就可以构建java对象,所以SAX看起来是自然的选择。我正在扩展DefaultHandler并实现startElement、endElement和characters方法,在我的类中有成员,在其中保存当前读取值(在characters方法中获取) 我在做我需要的事情上没有问题,但是我的代码变得相当复杂,我确信没有理由这样做,我可以用不同的方式来做事情。 我的XML的结构如下所示: <players> <player>

我需要解析一个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>
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);
        }
    }
}

2009
9
真的
2007
11
2009
7.
当我意识到文件的几个区域使用相同的标记名时,我的问题就开始了。例如,球员和球队都有id和名称。我想创建我的java类播放器和团队的实例。在解析时,我保留布尔标志告诉我是否在团队部分,以便在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;
        }
    }
}
公共类MyParser扩展了DefaultHandler{
私有字符串currentValue;
私有布尔值inTeamsSection=false;
私人玩家;
私人团队;
私人名单小组;
公共无效字符(char[]ch,int start,int length)引发异常{
currentValue=新字符串(ch、开始、长度);
}
public void startElement(字符串uri、字符串localName、字符串名称、属性)引发SAXException{
如果(名称等于(“玩家”)){
player=新玩家();
}
如果(名称等于(“团队”)){
inTeamsSection=true;
团队=新的ArrayList();
}
如果(名称等于(“团队”)){
团队=新团队();
}
}   
公共void endElement(字符串uri、字符串localName、字符串名称)引发SAXException{
如果(名称等于(“id”)){
国际单项体育联合会(国际单项体育联合会){
team.setId(当前值);
}
否则{
player.setId(当前值);
}
}
如果(名称等于(“名称”)){
国际单项体育联合会(国际单项体育联合会){
team.setName(currentValue);
}
否则{
player.setName(当前值);
}
}
如果(名称等于(“团队”)){
团队。添加(团队);
}
如果(名称等于(“团队”)){
球员。二传(队);
inTeamsSection=false;
}
}
}
因为在我的真实场景中,除了团队之外,我还有更多的玩家节点,这些节点也有像name和id这样的标签,我发现自己被几个类似于inTeamsSection的boolean搞得一团糟,我的endElement方法在许多情况下变得冗长而复杂

我应该怎么做?例如,我如何知道名称标签属于什么


谢谢

我强烈建议您停止自己解析,抓取好的XML数据绑定库。XStream()可能是个人的最爱,但有许多不同的库。它甚至可以当场解析POJO,而无需任何配置(如果您使用属性名和多元化来匹配XML结构)

我强烈建议您停止自己解析,抓取好的XML数据绑定库。XStream()可能是个人的最爱,但有许多不同的库。它甚至可以当场解析POJO,而无需任何配置(如果您使用属性名和多元化来匹配XML结构)

我做了一些非常类似的事情,但是我没有使用
布尔
标志来告诉我处于什么状态,而是测试
玩家
团队
是否为非
。让事情变得更整洁。这要求您在将每个元素添加到相关列表后,在检测到每个元素的结尾时,将它们设置为
null

我做了一些非常类似的事情,但不是使用
布尔
标志来告诉我处于什么状态,而是测试
玩家
团队
是否为非
null
。让事情变得更整洁。这要求您在将每个元素添加到相关列表后,在检测到每个元素的结尾时将其设置为
null

如果您需要更漂亮的代码,请使用StAX,这表明StAX是一个更好的选择

在大多数测试中,它也优于任何其他API实现


因此,我个人认为没有任何理由继续使用SAX,除非您正在进行一些与遗留相关的编程。

如果您需要更漂亮的代码,请使用StAX,这表明StAX是一个更好的选择

在大多数测试中,它也优于任何其他API实现


因此,我个人认为没有任何理由继续使用SAX,除非您正在进行一些与传统相关的编程。

在编写SAX解析器时,有一个巧妙的技巧:允许更改 解析时XMLReader的
ContentHandler
。这允许将 将不同元素的逻辑解析为多个类,这使得 解析更加模块化和可重用。当一个处理程序看到它的结束元素时 切换回其父级。您要实现多少个处理程序 你。代码如下所示:

<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>
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);
        }
    }
}
公共类RootHandler扩展了DefaultHandler{
私有XMLReader;
私人名单小组;
公共根处理程序(XMLReader){
this.reader=读取器;
this.teams=newlinkedlist();
}
public void startElement(字符串uri、字符串localName、字符串名称、属性)引发SAXException{
如果(名称等于(“团队”)){
//用于分析团队元素的开关处理程序
reader.setContentHandler(新TeamHa