【问题标题】:XmlPullParser - Parse nested tagXmlPullParser - 解析嵌套标签
【发布时间】:2015-02-09 11:59:58
【问题描述】:

我有这个 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();
    }

【问题讨论】:

    标签: java android arrays xmlpullparser android-xmlpullparser


    【解决方案1】:
           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];
        }
    
    }
    

    【讨论】:

    • 我在onProgressUpdate中改变了什么
    • 好的,我认为发布进度需要有所不同,因为当我在 onProgressUpdate 中添加日志时,它会记录多次
    • 我如何不获取所有嵌套标签,只获取某一天以下的标签?你能看看这个问题吗,stackoverflow.com/questions/27476359/…
    【解决方案2】:

    好吧,现在就从逻辑上看一下你的 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】:

    主要思想

    将您的信息存储在局部变量中,然后检查访问的标签是否等于您想要的模式,如果是,请执行您想要的操作。这是想法:

      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】:

      首先,您的 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);
      }
      

      }

      【讨论】:

        【解决方案5】:

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

        结束标签应该是这样的

        不是=>

        将 XML 更正为下面的 response 字符串后, 你可以试试这段代码,它的工作原理

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

        希望这会有所帮助!

        【讨论】:

        • 所以基本上你建议不要使用 XMLPullParser 来获取嵌套标签?
        【解决方案6】:

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

        一个帮助你前进的非常简单的例子:

        我解析了这个字符串:

        &lt;menu&gt;&lt;day name=\"monday\"&gt;&lt;meal name=\"BREAKFAST\"&gt;&lt;meal/&gt;&lt;day/&gt;&lt;/menu&gt;

        代码:

        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 可帮助您以良好的方式编写逻辑。

        希望这会有所帮助。

        【讨论】:

          【解决方案7】:

          使用 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;
          }
          }
          

          【讨论】:

            猜你喜欢
            • 2013-03-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-13
            • 2016-06-03
            • 2015-03-14
            • 1970-01-01
            • 2011-09-24
            相关资源
            最近更新 更多