一种迭代XML树并从中提取数据的简单方法?

时间:2012-05-05 00:54:51

标签: java xml dom sax

假设我的XML树中有四个级别,其中级别3可以有相同的子级 - 两次,即 在以下XML中:

<Game>
    <Round>
        <roundNumber>1</roundNumber>
        <Door>
            <doorName>abd11</doorName>
            <Value>
                <xVal1>0</xVal1>
                <xVal2>25</xVal2>
                <pVal>0.31</pVal>
            </Value>
            <Value>
                <xVal1>25</xVal1>
                <xVal2>50</xVal2>
                <pVal>0.04</pVal>
            </Value>
            <Value>
                <xVal1>50</xVal1>
                <xVal2>75</xVal2>
                <pVal>0.19</pVal>
            </Value>
            <Value>
                <xVal1>75</xVal1>
                <xVal2>100</xVal2>
                <pVal>0.46</pVal>
            </Value>
        </Door>
        <Door>
            <doorName>vvv1133</doorName>
            <Value>
                <xVal1>60</xVal1>
                <xVal2>62</xVal2>
                <pVal>1.0</pVal>
            </Value>
        </Door>
    </Round>
    <Round>
        <roundNumber>2</roundNumber>
        <Door>
            <doorName>eee</doorName>
            <Value>
                <xVal1>0</xVal1>
                <xVal2>-25</xVal2>
                <pVal>0.31</pVal>
            </Value>
            <Value>
                <xVal1>-25</xVal1>
                <xVal2>-50</xVal2>
                <pVal>0.04</pVal>
            </Value>
            <Value>
                <xVal1>-50</xVal1>
                <xVal2>-75</xVal2>
                <pVal>0.19</pVal>
            </Value>
            <Value>
                <xVal1>-75</xVal1>
                <xVal2>-100</xVal2>
                <pVal>0.46</pVal>
            </Value>
        </Door>
        <Door>
            <doorName>cc</doorName>
            <Value>
                <xVal1>-60</xVal1>
                <xVal2>-62</xVal2>
                <pVal>0.3</pVal>
            </Value>
            <Value>
                <xVal1>-70</xVal1>
                <xVal2>-78</xVal2>
                <pVal>0.7</pVal>
            </Value>
        </Door>
    </Round>
</Game>

每个Doors我有两个Round,那么问题是,使用DomSax(或Jdom,如果它有帮助)可以

我迭代我的树并获得每个级别的数据?

此刻,我“降低”并获得了回合,在这里:

  DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    Document doc = docBuilder.parse (new File("input.xml"));

    // normalize text representation
    doc.getDocumentElement ().normalize ();
    System.out.println ("Root element of the doc is " +    // would produce Game
         doc.getDocumentElement().getNodeName());


    NodeList roundNodes = doc.getElementsByTagName("Round");   // roundNodes are the Rounds 
    int totalNodes = roundNodes.getLength();                   // 2 by the example 
    System.out.println("Total number of Rounds are : " + totalNodes);   


    for (int i = 0; i < roundNodes.getLength() ; i++)

    {
        Node node = roundNodes.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE)
        {
            Element element = (Element)node;
            NodeList firstDoorList = element.getElementsByTagName("Door");
            Element firstDoorElement = (Element)firstDoorList.item(0);

            NodeList textFNList = firstDoorElement.getChildNodes();
            System.out.println("First Door : " + ((Node)textFNList.item(0)).getNodeValue().trim());
        }
    }

但似乎迭代的代码很多。

是否有一种简单的方法来提取该XML的数据?假设我每轮有2个门,有些轮数。

谢谢

1 个答案:

答案 0 :(得分:2)

解析这样的内容是我写SJXP的原因之一 - 我知道,我知道“哦,上帝,不是另一个家庭酿造的图书馆!”,但不要绝望,这很容易 - to-use库构建在STAX解析器规范的ontop上,因此您不会获得使用DOM轻松完成的开销。我把它作为手写源解析器(RDF,RSS,ATOM)一年多来的结果,并且意识到我的工作越复杂,它就越相似,所以我把核心租户简化为一个,简单快速的库(开销小于SAX解析器 - 它也可以在Android上运行,没有添加依赖项)。

库的要点是定义一系列规则,这些规则针对您想要的XML中的所有元素。鉴于您要解析的所有XML数据都是CHARACTER数据(不是标记内部的属性数据),您可以定义一系列字符规则,如下所示:

IRule roundNumRule = new DefaultRule(Type.CHARACTER, "/Game/Round/roundNumber") {
    @Override
    public void handleParsedCharacters(XMLParser parser, String text, Object userObject) {
        System.out.println("Round Parsed: " + text);
    }
}

IRule doorNameRule = new DefaultRule(Type.CHARACTER, "/Game/Round/Door/doorName") {
    @Override
    public void handleParsedCharacters(XMLParser parser, String text, Object userObject) {
        System.out.println("Door Name: " + text);
    }
}

......依此类推 - 其他规则的路径如下所示:

  • /游戏/回合/门/值/ xVal1
  • /游戏/回合/门/值/ xVal2
  • /游戏/回合/门/值/ PVAL

在你掌握了所有规则之后,你会像这样创建一个XMLParser instance,给它你创建的所有规则:

XMLParser parser = new XMLParser(roundNumRule, doorNameRule, <more rules>);

然后使用它来解析XML,方法是通过parse methods之一提供代表XML流的任何有效 InputStream 实例。

您可以安全地重复使用XMLParser实例(不是同时在单独的线程中)。

你需要跟踪你的状态,因为你知道你正在为哪个roundNumber加载门值以及用哪些值填充哪个门,但这很容易做 - 只需创建简单的Java POJO表示您的结构并将它们存储在ArrayList中,例如:

List<Round> roundList = new ArrayList<Round)();

说你的“回合”POJO看起来像这样:

public class Round {
    public int number;
    public List<Door> doorList;
}

你的门POJO看起来像是:

public class Door {
    public String name;
    public int xVal1;
    public int yVal2;
    public double pVal;
}

顶级 roundList 将代表已解析值的根,您可以将其直接传递给解析操作;这是您在SJXP Javadocs中引用的 userObject

当规则匹配时会发生什么,它会将userObject传递给规则,这样您就可以访问传入的列表。

对于roundNumRule - 您将创建一个新的Round POJO,为其指定roundNumber值并将其添加到列表中。

对于doorNameRule - 你将从列表中拉出最后一轮,向它添加一个新的POJO并为其指定名称。

等等......

我希望有所帮助!