Android - синтаксический анализ XML - работает на эмуляторе, но не на устройстве

В моем приложении я разбираю xml, часть структуры, создающая проблемы:

<answers>
    <answer value="A">A</answer>
    <answer value="B">B</answer>
    <answer value="C">C</answer>
</answers>

Я разбираю его с помощью XML DOM:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(url.openStream()));
doc.getDocumentElement().normalize();

это прекрасно работает, и в зависимости от элементов ответа я создаю RadioButtons следующим образом:

NodeList answers = doc.getElementsByTagName("answers").item(0).getChildNodes();

int j = 0;
RadioGroup group = new RadioGroup(this);
RadioButton button1 = new RadioButton(this);
button1.setId((i+1)*100+(j++));
button1.setText(answers.item(1).getChildNodes().item(0).getNodeValue());
button1.setTextColor(Color.BLACK);

RadioButton button2 = new RadioButton(this);
button2.setId((i+1)*100+(j++));
button2.setText(answers.item(2).getChildNodes().item(0).getNodeValue());
button2.setTextColor(Color.BLACK);

RadioButton button3 = new RadioButton(this);
button3.setId((i+1)*100+(j));
button3.setText(answers.item(3).getChildNodes().item(0).getNodeValue());
button3.setTextColor(Color.BLACK);

Этот фрагмент кода отлично работает в эмуляторе SDK v.7 (Android 2.0), в то время как мой HTC Desire работает на Android 2.1u1 (так что SDK v.8)

Но в устройстве я получаю ошибку в этой строке button2.setText(answers.item(2).getChildNodes().item(0).getNodeValue());, предполагая, что в ответах нет .item(2), но это должно быть... Я отлаживал этот код в эмуляторе и обнаружил, что answers.item(0) - это TextNode, содержащий имя узла XML "ответы"...

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

Нет ли чего-то похожего на SimpleXml из PHP в Java???

Во всяком случае, моя главная проблема: как возможно, что приложение отлично работает в эмуляторе, в то время как на устройстве оно выдает NullPointerException в строке, где я пытаюсь установить текст для кнопки2???

Большое спасибо за помощь!!!


person shadyyx    schedule 05.05.2011    source источник
comment
О, и когда я выводил значение setText() непосредственно на устройство, button1.setText(answers.item(1).getChildNodes().item(0).getNodeValue()); обрабатывалось без ошибок и значение выводилось, а следующий элемент button2.setText(answers.item(2).getChildNodes().item(0).getNodeValue()); выдавал ошибку... Поэтому я вообще не понимаю...   -  person shadyyx    schedule 05.05.2011
comment
Мой совет: перестаньте использовать построитель документов для анализа XML в Android, используйте вместо этого простую библиотеку (simple.sourceforge.net) и вот сообщение в блоге об этом (massaioli.homelinux.com/wordpress/2011/04/21/)   -  person Robert Massaioli    schedule 06.05.2011
comment
@RobertMassaioli: Хм, я посмотрел на это, это выглядит красиво, но все же не очень просто — вам нужно написать и определить класс для КАЖДОГО объекта в XML (то есть для каждого ТЕГА) — где упрощение??? Да, возможно, при разборе XML это проще, но Вам придется сгенерировать, может быть, в два раза больше кода... НО - я попробую, когда останется немного времени...   -  person shadyyx    schedule 06.05.2011
comment
@shadyyx Это неправда, вам не нужно писать класс для каждого тега. Взгляните на аннотацию пути в Simple, она позволяет отображать несколько вложенных элементов и атрибутов XML с помощью выражений XPath.   -  person ng.    schedule 31.08.2011


Ответы (2)


getChildNodes() возвращает все Node под ответами, а не только все Element. Вы, вероятно, захотите перебрать все дочерние элементы и проверить, является ли каждый из них Element с именем тега "ответ"

Как насчет такого:

NodeList answers = doc.getElementsByTagName("answer");
for (int x = 0; x < answers.getLength(); x++) {
  Node answer = answers.get(x);
  // you could do some checking here, make sure Node is instanceof Element, etc.
  RadioButton radioButton = new RadioButton(this);
  radioButton.setId((i+1)*100+(x));
  radioButton.setText(node.getNodeValue());
  radioButton.setTextColor(Color.BLACK);
  // add the radio button to some view
}

Таким образом, вы не зависите от определенного количества дочерних элементов ответов и гарантируете, что не попытаетесь получить доступ к несуществующему элементу.

Если вы действительно хотите сделать это на основе дочерних узлов узла «Ответы»,

Node answersNode = // get the node
NodeList childNodes = answersNode.getChildNodes();
for (int x = 0; x < childNodes.getLength(); x++) {
  Node node = childNodes.get(0);
  if (node instanceof Element && node.getNodeName().equals("answer")) {
    // do the same as above to create a radio button.
  }
}
person Cheryl Simon    schedule 05.05.2011
comment
Таким образом, вы не зависите от определенного количества дочерних элементов ответов и гарантируете, что не попытаетесь получить доступ к несуществующему элементу. - это правда, и я знаю об этом решении, но всегда будет только и только три элемента ответа в каждом элементе ответов, поэтому я знаю, что нужно создать только три RadioButton. В любом случае, спасибо за помощь, особенно за часть проверки имени тега - мне это никогда не приходило в голову... Я решил проблему по-другому, и проблема была в основном в PHP-скрипте... (продолжение в следующем комментарии) - person shadyyx; 06.05.2011
comment
... создание XML - я использовал \n для разделения строк, которые генерируют еще один узел TextImpl, содержащий \n\n\n\n в эмуляторе, которого (каким-то образом) не было в реальном устройстве... После удаления каждого \n из PHP-скрипта парсинг в эмуляторе работает так же, как и в реальном устройстве... Поставил +1 за пост, но не могу пометить его как ответ, так как разобрался в другом месте и по-другому... Но спасибо! !! - person shadyyx; 06.05.2011
comment
Это звучит довольно хрупко. Пробелы не должны влиять на анализ xml. Даже если у вас всегда ровно 3 радиокнопки, все равно проще перебрать их, чем предполагать, что они существуют по какому-то индексу. - person Cheryl Simon; 06.05.2011

Использование (простой XML)[http://simple.sourceforge.net/]

@Root
public class Answers {

   @ElementMap(entry="answer", key="value" attribute="true" inline=true)
   public Map<String, String> map;
}

Или, если у вас есть только три записи, которые вы могли бы сделать.

@Root
public class Answers {

   @Path("answer[1]")
   @Text
   private answerValue1;

   @Path("answer[2]")
   @Text
   private answerValue2;

   @Path("answer[3]")
   @Text
   private answerValue3;

   @Path("answer[1]")
   @Attribute(name="value")
   private answerAttribute1;

   @Path("answer[2]")
   @Attribute(name="value")
   private answerAttribute2;

   @Path("answer[3]")
   @Attribute(name="value")
   private answerAttribute3;
}

Тогда читайте так.

Persister persister = new Persister();
Answers answers = persister.read(Answers.class, xml);

Просто как тот!!

person ng.    schedule 30.08.2011