Разбор XML для Android с разными именами элементов - PullRequest
0 голосов
/ 17 ноября 2010

Мне нужна помощь: D. Я использую веб-сервис, который возвращает XML-файл, аналогичный приведенному ниже:

<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» child - так что тогда я мог бы использовать SAX-парсер и получить список «item»

Ответы [ 3 ]

1 голос
/ 17 ноября 2010

Проблема, которую вы описали, звучит не так уж и сложно: Если , вы можете смело предположить, что каждый дочерний элемент элемента 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» теперь может быть дочерним по отношению к какому-либо другому элементу, например «департаментам», не требуя значительных изменений в этих классах.

Псевдокод не является идеальным для любогосредства.(Во-первых, я хотел бы еще немного подумать о том, где отключены обработчики - в родительском классе или в дочернем. Во-вторых, я мог бы зайти слишком далеко, сохранив ссылки на родителей и детей вэти классы.) Но я надеюсь, что это даст вам идеи, с которыми вы можете начать работать.

0 голосов
/ 17 ноября 2010

Это выглядит как очень странный формат 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
        }
    }
0 голосов
/ 17 ноября 2010

Я ранее использовал 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, которые должны содержать материал, с которым вы хотите поиграть.

Спасибо,

ElDog

...