XmlPullParser - 解析嵌套标记

时间:2014-12-11 04:37:25

标签: java android arrays xmlpullparser android-xmlpullparser

我有这个XML:

<menu>
    <day name="monday">
        <meal name="BREAKFAST">
            <counter name="Bread">
               <dish>
                   <name>Plain Bagel</name>
               </dish>
            <counter/>
        <meal/>
    <day/>
    <day name="tuesday">
        <meal name="LUNCH">
            <counter name="Other">
               <dish>
                   <name>Cheese Bagel</name>
               </dish>
            <counter/>
        <meal/>
    <day/>
<menu/>

如果day标签的属性等于星期一,那么现在就是我要做的。然后,饭标标记属性等于BREAKFAST,然后我想得到计数器的属性。 &#34;面包&#34;

我已经设置了xml pull解析器,但我很难获得这个值。这是我尝试过的,现在我看到它无法工作......所以任何有关如何设置它的帮助都会很棒。

while (eventType != XmlResourceParser.END_DOCUMENT) {
        String tagName = xmlData.getName();

        switch (eventType) {
            case XmlResourceParser.START_TAG:
                if (tagName.equalsIgnoreCase("day")) {
                    if (xmlData.getAttributeValue(null, "name").equalsIgnoreCase(day)) {
                        if (tagName.equalsIgnoreCase("meal")) {
                            mealArray.add(xmlData.getAttributeValue(null, "name"));
                            Log.i(TAG, xmlData.getAttributeValue(null, "name"));
                        }
                    }


                }
                break;
            case XmlResourceParser.TEXT:
                break;
            case XmlPullParser.END_TAG:

                break;
        }
        eventType = xmlData.next();
    }

7 个答案:

答案 0 :(得分:6)

您需要添加用于解析嵌套标记的逻辑:

帮助您前进的一个非常简单的示例:

我解析了这个字符串:

<menu><day name=\"monday\"><meal name=\"BREAKFAST\"><meal/><day/></menu>

代码:

try {
    factory = XmlPullParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XmlPullParser xpp = factory.newPullParser();

    xpp.setInput(new StringReader("<menu><day name=\"monday\"><meal name=\"BREAKFAST\"><meal/><day/></menu>"));
    int eventType = xpp.getEventType();
    while (eventType != XmlResourceParser.END_DOCUMENT) {
        String tagName = xpp.getName();

        switch (eventType) {
            case XmlResourceParser.START_TAG:
                if (tagName.equalsIgnoreCase("day")) {
                    if (xpp.getAttributeValue(null, "name").equalsIgnoreCase("MONDAY")) {
                        int eventType2 = xpp.next();
                        while (eventType2 != XmlResourceParser.END_DOCUMENT) {
                            String tagName2 = xpp.getName();
                            switch (eventType2) {
                            case XmlResourceParser.START_TAG:
                                if (tagName2.equalsIgnoreCase("meal")) {
                                    Log.i("tag", "meal: " + xpp.getAttributeValue(null, "name"));
                                }
                                break;
                            case XmlResourceParser.TEXT:
                                break;
                            case XmlPullParser.END_TAG:
                                break;
                            }
                            eventType2 = xpp.next();
                        }
                    }
                }
            break;
            case XmlResourceParser.TEXT:
            break;
            case XmlPullParser.END_TAG:
            break;
        }
        eventType = xpp.next();
    }

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

你看到了区别,对吧?

我添加了这个,基本上就是在获得我想要的那一天之后。 (就我而言,硬编码字符串"Monday"。)

int eventType2 = xpp.next();

并以此eventType2为基础,检索tagName2将用于“用餐”

一个better example来帮助你以一种很好的方式编写你的逻辑。

希望这有帮助。

答案 1 :(得分:5)

首先,您的XML格式不正确。 在任何网站查看。说这个XML Validator

结束标记应该是这样的

  

&LT;饭> &LT; /饭&gt;

     

不=&gt; &LT;饭&gt;&lt;饭/&gt;

在下面将XML更正为响应字符串后, 你可以尝试这个代码,它的工作

    String response = "<menu><day name=\"monday\"><meal name=\"BREAKFAST\"><counter name=\"Bread\"><dish><name>Plain Bagel</name></dish></counter></meal></day><day name=\"tuesday\"><meal name=\"LUNCH\"><counter name=\"Other\"><dish><name>Cheese Bagel</name></dish></counter></meal></day></menu>";
    Document doc;
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    InputSource isr = new InputSource();
    isr.setCharacterStream(new StringReader(response));

    doc = db.parse(isr);

    try{
        doc.getDocumentElement().normalize();
        NodeList nodes = doc.getElementsByTagName("day");
        for (int i = 0; i <= nodes.getLength(); i++) {
            Node nNode = nodes.item(i);

            if (nNode.getNodeType() == Node.ELEMENT_NODE) {


                Element eElement = (Element) nNode;
                System.out.println("day"+eElement.getAttribute("name"));
                System.out.println("meal"+eElement.getElementsByTagName("meal").item(0).getAttributes().getNamedItem("name").getNodeValue());
                System.out.println("counter"+eElement.getElementsByTagName("counter").item(0).getAttributes().getNamedItem("name").getNodeValue());
                System.out.println("dish :" + eElement.getElementsByTagName("name").item(0).getTextContent());

            }
        }

    }
    catch(Exception e){

    }

希望这有帮助!

答案 2 :(得分:3)

好吧,现在就逻辑地看一下你的switch语句:

String tagName = xmlData.getName();


            if (tagName.equalsIgnoreCase("day")) {
                if( . . . ) {
                    if (tagName.equalsIgnoreCase("meal")) {
                      //do something
                    }
                }

你看到那个问题吗?你永远不会tagName.equals("day")tagName.equals("meal")都是真的!继续获取xmlData的子节点并获取它的名称,然后执行另一个if语句。

您需要在每个if之后更新tagName的值。

答案 3 :(得分:3)

主要想法

将您的信息存储在本地变量中,然后检查访问过的标签是否与您想要的模式相同,如果是,请执行您想要的操作。这是一个想法:

  String currentDay;
  String mealOfCurrentDay;

  while (eventType != XmlResourceParser.END_DOCUMENT) {
        String tagName = xmlData.getName();

        switch (eventType) {
            case XmlResourceParser.START_TAG:
                if (tagName.equalsIgnoreCase("day")) 
                       currentDay = xmlData.getAttributeValue(null, "name");
                }
                if (tagName.equalsIgnoreCase("meal")) 
                       mealOfCurrentDay = xmlData.getAttributeValue(null, "name");
                }
                if (tagName.equalsIgnoreCase("counter ")){
                    // now we must check our stored pattern
                    // step one: day must be monday
                    if(currentDay != null && currentDay.equalsIgnoreCase("monday")){
                         // step tow: meal must be BREAKFAST
                         if(mealOfCurrentDay!= null && mealOfCurrentDay.equalsIgnoreCase("BREAKFAST")){
                              counter = xmlData.getAttributeValue(null, "name");
                              // Wow we have done :-)
                         }
                         else{
                          // no, it is not my desierd pattern so I clear my history
                             currentDay = "";
                             mealOfCurrentDay = "";
                         }  
                    }else{
                        // no, it is not my desierd pattern so I clear my history
                        currentDay = "";
                        mealOfCurrentDay = "";
                    }
                }
                break;
            case XmlResourceParser.TEXT:
                break;
            case XmlPullParser.END_TAG:

                break;
        }
        eventType = xmlData.next();
    }

答案 4 :(得分:2)

       while (eventType != XmlResourceParser.END_DOCUMENT) {
        String tagName = xmlData.getName();

        switch (eventType) {
           case XmlResourceParser.START_TAG:
                if (tagName.equalsIgnoreCase("day")) {
                    day = xmlData.getAttributeValue(null, "name");
                }
                if (tagName.equalsIgnoreCase("meal")) {
                    meal = xmlData.getAttributeValue(null, "name");
                }
                if (tagName.equalsIgnoreCase("counter")) {
                    counter = xmlData.getAttributeValue(null, "name");
                }

                break;
            case XmlResourceParser.TEXT:
                data += xmlData.getText();
                if (tagName.equalsIgnoreCase("name")) {
                    name= xmlData.getText();
                }
                break;
            case XmlPullParser.END_TAG:
                if (tagName.equals("day")) {
                    recordsFound++;

                }
                break;
        }
        publishProgress(new String[]{day,meal,counter});
        eventType = xmlData.next();

    }

首先,switch-case语句中缺少中断。 其次,始终从START_TAG案例中解析属性。标签内的文本在TEXT情况下解析,END_TAG对于根据其嵌套制作对象或arraylists非常有用。

onProgressUpdate必须如下所示:

@Override
protected void onProgressUpdate(String... values) {
   super.onProgressUpdate(values);
   if (values.length == 0) {
        Log.i(TAG, "no data");
    }
    else {
       String day = values[0];
       String meal= values[1];
       String counter= values[2];
    }

}

答案 5 :(得分:2)

首先,您的XML已损坏,请查看结束标记。应该是:

<menu>
<day name="monday">
    <meal name="BREAKFAST">
        <counter name="Bread">
           <dish>
               <name>Plain Bagel</name>
           </dish>
        </counter>
    /</meal>
</day>
<day name="tuesday">
    <meal name="LUNCH">
        <counter name="Other">
           <dish>
               <name>Cheese Bagel</name>
           </dish>
       </counter>
    </meal>
</day>

其次,考虑使用不是拉解析器,你使用了很多代码行,但是你的目标有更短的方法(例如XMLBeam披露:我隶属于该项目)):

public class Test {
@XBDocURL("res://menu.xml")
public interface Menu {
    @XBRead("//day[@name='monday']/meal[@name='BREAKFAST']/counter/@name")
    String getCounterName();
}

@Test
public void testMenu() throws IOException {
    String name = new XBProjector().io().fromURLAnnotation(Menu.class).getCounterName();
    assertEquals("Bread", name);
}

}

答案 6 :(得分:2)

使用XPath并保持平静

package xml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

public class XPathTest {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("sample.xml");

    XPathFactory xpathfactory = XPathFactory.newInstance();
    XPath xpath = xpathfactory.newXPath()
XPathExpression expr = xpath.compile("string(/menu/day[@name='monday']/meal[@name='BREAKFAST']/counter/@name))");
    Object result = expr.evaluate(doc, XPathConstants.NODESET);
return (String)result;
}
}