9

我有这个 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 标签的属性等于 monday,那么这就是我想要做的。然后饭菜标签属性等于BREAKFAST,然后我想获取计数器的属性。“面包”。

我已经设置了 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();
    }
4

7 回答 7

7

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

一个非常简单的示例可以帮助您继续前进:

我解析了这个字符串:

<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();
}

你看到区别了,对吧?

基本上,我在得到我想要的那一天之后添加了这个。(在我的情况下,硬编码 String "Monday"。)

int eventType2 = xpp.next();

并基于此eventType2,检索tagName2到“用餐”

一个更好的例子来帮助你以一种很好的方式编写你的逻辑。

希望这可以帮助。

于 2014-12-19T14:01:36.887 回答
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 语句。

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

于 2014-12-15T02:57:13.180 回答
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();
    }
于 2014-12-15T04:08:39.463 回答
3

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

结束标签应该是这样的

<一顿></膳食>

不是=><吃饭><吃饭/>

将 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){
        
    }

希望这可以帮助 !

于 2014-12-18T10:59:29.443 回答
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 可用于基于其嵌套创建对象或数组列表。

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];
    }

}
于 2014-12-11T04:55:38.487 回答
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);
}

}

于 2014-12-15T13:04:19.407 回答
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;
}
}
于 2014-12-21T20:09:17.520 回答