【问题标题】:parsing XML in Java with identical parent and child tags用相同的父子标签在Java中解析XML
【发布时间】:2011-03-18 19:57:56
【问题描述】:

我一直在尝试在 Android 上构建一个从 Labview RestFUL 服务器获取数据的应用。到目前为止,我已经完成了相当多的工作,但是当我需要解析数组中的数据(名为 Probability)时,我陷入了困境。显示了 XML 代码的 sn-p:

<Response>
    <Terminal>
        <Name>Push</Name>
        <Value>77.678193</Value>
    </Terminal>
    <Terminal>
        <Name>Pull</Name>
        <Value>153.621879</Value>
    </Terminal>
(snip)
    <Terminal>
        <Name>Probability</Name>
        <Value>
            <DimSize>480</DimSize>
            <Name>effect</Name>
            <Value>0.000000</Value>
            <Name>effect</Name>
            <Value>0.000000</Value>
            <Name>effect</Name>
(snip)
        </Value>
    </Terminal>
</Response>

正如你所见,LabView 使用了一个嵌套的值标签。

我一直在使用标准的 XML 解析技术,但没有奏效(如果我在父节点中搜索“值”,它会返回同一个父节点)。所以我开始使用更多创造性的技术,但没有好的结果。例如下面的代码,我调用if ( lName == "Value") 只是发现 lName 设置为 Null。

有什么建议吗?

InputStream firstData = null;
URL url = null;
try {
    url = new URL(urlString);
} catch (MalformedURLException e2) {
    // TODO Auto-generated catch block
    e2.printStackTrace();
} 
int response = -1;


try {
    URLConnection conn = url.openConnection();
    Document doc = null;
    DocumentBuilderFactory dbf = 
        DocumentBuilderFactory.newInstance();
    DocumentBuilder db;

    HttpURLConnection httpConn = (HttpURLConnection) conn;
    httpConn.setAllowUserInteraction(false);
    httpConn.setInstanceFollowRedirects(true);
    httpConn.setRequestMethod("GET");
    httpConn.connect(); 

    response = httpConn.getResponseCode();                 
    if (response == HttpURLConnection.HTTP_OK) {
        firstData = httpConn.getInputStream();                                 
    }                     

    try {
        db = dbf.newDocumentBuilder();
        doc = db.parse(firstData);
    } catch (ParserConfigurationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SAXException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }        

    doc.getDocumentElement().normalize(); 

    NodeList terminalNodes = doc.getElementsByTagName("Terminal"); 

    for (int i = 0; i < 4; i++) { 
        Node singleTerminalNode = terminalNodes.item(i); 
        if (singleTerminalNode.getNodeType() == Node.ELEMENT_NODE) 
        {            
            Element firstLevel = (Element) singleTerminalNode;

            NodeList value1Nodes = (firstLevel).getElementsByTagName("Value");

            Element value1Element = (Element) value1Nodes.item(0);

            if (i<FIRST_SET){
                NodeList digit1Nodes = ((Node) value1Element).getChildNodes();
                hinde[i] = Double.parseDouble(((Node) digit1Nodes.item(0)).getNodeValue());
            }
            else 
                {
                NodeList value1Children = ((Node) value1Element).getChildNodes();

                int henry = value1Children.getLength();
                int counter = 0;
                String lName;



                for (int j = 0; i < henry; j++){                

                    Element digit2Element = (Element) value1Children.item(j);
                    lName = digit2Element.getLocalName();
                    if ( lName == "Value")
                    {
                    NodeList digit2Nodes = ((Node) digit2Element).getChildNodes();
                    sweep[counter] = Double.parseDouble(((Node) digit2Nodes.item(0)).getNodeValue());
                    counter ++;
                    }
                }
                }
        } 
    }   
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();            
}

【问题讨论】:

  • 我不知道这是否是你的问题,但你不应该使用 == 来比较字符串。使用 .equals 代替。 == 只有当边是同一个对象时才为真,如果两个东西是等价的对象(即具有相同的字符串值),.equals 才为真。
  • 嗨 Mayra,它甚至没有达到字符串比较:调试时,可悲的事实仍然是 lName 为空(我在 IF 语句中使用了断点触发)
  • 使用 SAX 而不是 DOM,您可能会更轻松地解析它,并获得更好的启动性能。正如@Mayra 指出的那样,请确保不要使用== 来比较字符串。

标签: java xml xml-parsing


【解决方案1】:

我想这可以使用 DOM 解析器来完成,但使用 SAX 或 STAX 解析器可能更容易实现(它也会有更小的内存印记!)。

http://download.oracle.com/javase/1.4.2/docs/api/javax/xml/parsers/SAXParser.html

http://download.oracle.com/javaee/5/tutorial/doc/bnbem.html

使用 SAX,您可以创建一个处理程序,该处理程序将在解析器到达文档中的某些点时接收事件。使用可以嵌入的标签,您可以使用处理程序来维护光标的状态。例如,当您看到第一个标签时,您可能有一个表示标签“级别”的 int。

使用 STAX,您可以流式传输事件,并且只需要处理您感兴趣的事件。如果您对“开始元素事件”感兴趣,您可以获得它们,并保持光标的状态类似于您可以使用 SAX 解析器。

【讨论】:

  • Android 上没有 stax :( 我看看能不能让 SAX 运行
【解决方案2】:

正如 nicholas.hauschild 所提到的,您可以使用 SAX 解析器来执行此操作。但我认为您不需要 level 变量来区分这两个标签。

只要有要读取的数据,它就会调用 characters() 方法,您可以从中读取值。由于父 &lt;Value&gt; 标签没有任何自己的数据(嵌套标签除外),它不会调用 characters() 方法。

【讨论】:

  • 我想你仍然需要保持某种状态,就像在拉斯曼的例子中一样,你会在顶级 元素中点击多个字符部分,而 characters() 方法没有提到它的直接父母(或任何父母)是什么。
  • 对不起 - 我不明白为什么你需要知道级别,characters() 方法只有在有数据要读取时才会调用,当有数据要读取时,你继续通过调用您的方法来阅读它。我可能在这里遗漏了一些东西,OP 一定已经找到了答案,所以我们不妨放手! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2012-10-21
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
  • 1970-01-01
相关资源
最近更新 更多