JAVA - 解析来自 XML 的特定数据

JAVA - parsing specific data from XML

有很多页面解释 XML,但我还没有找到任何内容来解决我的特定问题。我有一个 XML 文件,它定义了我正在开发的一个简单游戏的所有项目。因为我不想一直加载整个地图,所以我也不需要一直加载游戏中的每个项目。只是我正在使用的地图部分中的那些。我知道 SAX 是最好的方法。基本上我想做的是拥有这样的东西:

<item>
    <id>12345</id>
    <name>note</name>
    <weight>.1</weight>
</item>
<item>
     .......
</item>

我想编写一个函数,它可以获取项目 ID 的数组(从另一个特定于我当时正在加载的地图的列表中提取),并为每个给定的 ID 解析 xml 文件,然后当它找到一个项目标签,其 id 标签包含它要查找的 id 时,从该项目中的每个标签中获取数据并将其设置为变量(id、note 和 weight),我可以将其传递给构造函数方法.这样,我只构建相关的项目对象。但我不确定该怎么做。任何帮助将不胜感激。


编辑:

好的,我想我差不多已经弄明白了,但仍然 运行 遇到了问题。这是我的

public class SaxParsing {

    public static void main(String argv[]) {

        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();

            DefaultHandler handler = new DefaultHandler() {
                String foundName = null;
                int idGiven = 101002;
                boolean b_id = false;
                boolean b_idToFind = false;
                boolean b_name = false;

                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes)
                        throws SAXException {
                    if (localName.equalsIgnoreCase("id")) {
                        b_id = true;
                    }
                    if (localName.equalsIgnoreCase("name")) {
                        b_name = true;
                    }
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if (localName.equalsIgnoreCase("id")) {
                        b_id = false;
                    }
                    if (localName.equalsIgnoreCase("name")) {
                        b_name = false;
                    }
                    if (localName.equalsIgnoreCase("item")) {
                        b_idToFind = false;
                    }
                }

                public void characters(char buffer, int start, int length) throws SAXException {
                    if (b_id) {
                        String temp = new String();
                        temp = String.valueOf(buffer);
                        if (temp == Integer.toString(idGiven)) {
                            b_idToFind = true;
                        }
                    }
                    if (b_name) {
                        if (b_idToFind) {
                            foundName = new String();
                            foundName = String.valueOf(buffer);

                        }
                    }
                }
            };

            saxParser.parse("path\to\GameItems.xml", handler);
            System.out.println(foundName);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

一切正常,除了我无法访问 DefaultHandler 之外的变量 foundName。 NetBeans 给出 "can't find symbol" 错误。我觉得这是一个简单的范围问题,但我似乎无法解决它。

您无法访问 foundName,因为它是在 new DefaultHandler() { ... } 内部 class.

中声明的

您可以将 foundName 向上移动两行,在内部 class 之外,但是为了在内部 class 内部访问它,您需要将其 final,这使得它对你想要的东西毫无用处。

你想要的是类似 handler.foundName 的东西,但是 handler 被声明为 DefaultHandler 类型,它没有名为 foundName 的字段。您的内部 class 确实 具有该字段,但该类型没有类型名。你的问题就在这里。解决办法是把它变成一个成熟的 class:

class ItemHandler extends DefaultHandler {
    String foundName;
    public void startElement(...) {...}
    public void endElement(...) {...}
    public void characters(...) {...}
}

然后您可以将 handler 声明为 ItemHandler 类型,并获得访问其字段的能力:

ItemHandler handler = new ItemHandler();
saxParser.parse("path\to\GameItems.xml", handler);
System.out.println(handler.foundName);

作为旁注。您的 SAX 处理有缺陷。您不能保证在对 public void characters(char[] ch, int start, int length) 的一次调用中获得标记 <tag>yada,yada,yada</tag> 之间的所有字符( 请注意正确的签名 )。您应该只累积它们,并在结束标记中处理它们。类似于:

class ItemHandler extends DefaultHandler {
    int idGiven = 101002;
    String foundName = null;

    private StringBuilder sb = new StringBuilder();
    private String item_name;
    private int item_id;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attr) {
        sb.setLength(0); // Clear the buffer
    }

    @Override
    public void characters(char[] buffer, int start, int length) {
        sb.append(buffer, start, length);
    }

    @Override
    public void endElement(String uri, String localName, String qName) {
        switch(localName) {
          case "id":
            item_id = Integer.parseInt(sb.toString());
            break;
          case "name":
            item_name = sb.toString();
            break;
          case "item":
            if (item_id == idGiven) {
                foundName = item_name;
            }
            break;
          default:
            System.err.println("Unexpected tag: "+localName);
        }
        sb.setLength(0); // Clear the buffer
    }
}