【问题标题】:Android XML parsing with different element names使用不同元素名称解析 Android XML
【发布时间】:2010-11-18 19:07:57
【问题描述】:

我需要帮助:D。我正在使用将类似 xml 文件返回到以下文件的 Web 服务:

<books>
<item_1>
    <name></name>
    <type></type>
</item_1>
<item_2>
    <name></name>
    <type></type>
</item_2>
<item_3>
    <name></name>
    <type></type>
</item_3>
...
...</books>

问题是我不知道如何在 Android 中解析它。如果 'books' 标签的子元素具有相同的名称(item 而不是:item_1、item_2、item_3...),一切都会好起来的。然后我就可以轻松使用 SAX 解析器了。

你知道我如何在 Android 中修剪这种文档吗?

谢谢, 马克斯

已编辑:

我的问题是 books> 标签的子元素编号(item1、item2、item3 等),所以我无法识别它们。如果“books”标签只有“item”子级,那将不是问题——所以我可以使用 SAX 解析器并获取“item”列表

【问题讨论】:

  • 我不明白你的问题,你能详细说明一下吗?
  • 抱歉,我正在尝试解析 xml 文档(上面的那个) 目前我正在使用 SAX 解析器,但这不起作用,因为当我识别元素时: Element item = books.getChild ("item") 返回 null - 因为 XML 文档没有 'item' 标签,但有 'item1'、'item2'、'item3'...

标签: android xml parsing sax


【解决方案1】:

您所描述的问题听起来并不那么难:如果您可以安全地假设 books 元素的每个子元素都是一个“项目”,那么您可以调用您的“项目”处理程序”为每个孩子。

假设 始终是并且仅是文档的顶级元素,以下是(我认为)可行的伪代码:

class BookHandler extends DefaultHandler {
   public void startElement(String namespaceURI, String localName, 
                String qName, Attributes atts) {
        if (localName.equals("books") {
            // Don't need to do anything with the top level element
            return;
        }
        else {
            handleItem(namespaceURI, localName, qName, atts);
        }
    }

    public void  endElement(String namespaceURI, String localName, String qName) {
         if localName.equals("books") {
            // Stop parsing and exit.
         }
         else {
            // Stop parsing one item
         }
    }

    private void handleItem(String namespaceURI, String localName, 
                 String qName, Attributes atts) {
         // Handle one item, including handling the "name" and 
         // "type" child attributes
         if (localName.equals("name") {
            // handle the name
         }
         else if (localName.equals("type") {
            // handle the type
         }
    }
}

即使是伪代码,也过于简单和丑陋。另一种方法(但可能对您的需求过于夸张)是将您的应用程序分解为多个 ContentHandler 类,在您到达某些元素的开头或结尾时转移责任。

例如:假设 BookHandler 的一个实例被传递给 parser.parse() 调用,以处理顶级元素。那么:

class BookHandler extends DefaultHandler {
   private ContentHandler m_parentHandler;
   private ContentHandler m_childHandler = null;

   // ... == appropriate args for the DefaultHandler constructor
   public BookHandler(ContentHandler parent, Attributes atts, ...) {
        super(...);
        m_parentHandler = parent;
        parent.getXMLReader().setHandler(this);
   }

   public void startElement(String namespaceURI, String localName, 
                String qName, Attributes atts) {
        if (localName.equals("books") {
            // Don't need to do anything with the top level element
            return;
        }
        else {
            // Assume it's a new item element. (Note: ItemHandler's constructor
            // changes the parser's ContentHandler.)
            m_childHandler = new ItemHandler(this, atts, ...);
        }
    }

    public void  endElement(String namespaceURI, String localName, String qName) {
         if localName.equals("books") {
            // Stop parsing and exit.
         }
         else {
            // Note that this won't be called for "item" elements, UNLESS the
            // ItemHandler's endElement method explicitly invokes this method.

            // Stop parsing one item

         }
    }    
}


class ItemHandler extends DefaultHandler {
   private ContentHandler m_parentHandler;

    // ItemInfo is a class that holds all info about the current item
   private ItemInfo m_ItemInfo = null;

   // ... == appropriate args for the DefaultHandler constructor
   public ItemHandler(ContentHandler parent, Attributes atts, ...) {
        super(...);
        m_parentHandler = parent;
        m_ItemInfo = new ItemInfo(atts);
        parent.getXMLReader().setHandler(this);
   }

   public void startElement(String namespaceURI, String localName, 
                String qName, Attributes atts) {
        if (localName.equals("name") {
             // Handle the name. Update the current item as needed.
        }
        else  if (localName.equals("type") {
             // Handle the type. Update the current item as needed.
        }
    }

    public void  endElement(String namespaceURI, String localName, String qName) {
         if localName.equals("name" || localName.equals("type") {
             // Do nothing (?)
         }
         else {
            // Stop parsing the current item; 
            // let the parent class handle the next element.
            getXMLReader().setHandler(m_parentHandler);

            // OPTIONALLY -- depending on your app's needs -- call the
            // parent's endElement() method to let it know that we reached
            // the end of an item.
            m_parentHandler.endElement(namespaceURI, localName, qName);
         }
    }   
}

这种方案提供了更大的灵活性,以及​​更多的重用可能性。例如,“books”元素现在可能是某个其他元素(例如“departments”)的子元素,而无需对这些类进行太多更改。

伪代码无论如何都不是完美的。 (一方面,我想更多地考虑关闭处理程序的位置 - 在父类或子类中。另一方面,我可能在保存对父类和子类的引用方面做得过火了这些课程。)但我希望它能给你一些可以开始工作的想法。

【讨论】:

    【解决方案2】:

    我以前用过 DocumentBuilderFactory

    URL connectURL;
    InputStream is;
    NodeList names;
    NodeList types
    
    try
    {
      connectURL = new URL("http://example.com/exampleservice");
    
      try
      {
        URLConnection connection = connectURL.openConnection();
        is = connection.getInputStream();
      } catch (IOException e)
      {
        e.printStackTrace();
      }
    } catch (MalformedURLException e1)
    {
      e1.printStackTrace();
    }
    
    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    try
    {
      DocumentBuilder docBuillder = docBuilderFactory.newDocumentBuilder();
      Document doc = docBuillder.parse(is);
      names = doc.getElementsByTagName("name");
      types = doc.getElementsByTagName("type");
      } catch (ParserConfigurationException e)
      {
        e.printStackTrace();
      } catch (SAXException e)
      {
        e.printStackTrace();
      } catch (IOException e)
      {
        e.printStackTrace();
      }
    }
    

    这应该会产生 NodeLists,其中应该包含你想玩的东西。

    谢谢,

    埃尔狗

    【讨论】:

    • 等等,抱歉,我看到了您的问题。这是元素的编号。
    【解决方案3】:

    这似乎是一种非常奇怪的 XML 格式,无法为其编写架构。我假设你无法控制它?做类似的事情会更有意义。

    如果您使用的是 dom 解析器,您可以在不知道元素名称的情况下遍历元素树。从您的书籍元素中,只需致电getChildNodes

    使用 SAX 解析器,您只需在处理程序中查找包含 item 的元素名称,而不是完全等于 item。比如:

     public void startElement(String uri, String localName, String name,
                Attributes attributes) throws SAXException {
            super.startElement(uri, localName, name, attributes);
            if (localName.contains("item")){
                // create some item object
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-20
      • 1970-01-01
      • 2011-09-30
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      相关资源
      最近更新 更多