LINUX.ORG.RU

[Java]Помогите распарсить XML

 


0

0

Сразу к делу. Есть строка вида:

<?xml version="1.0" encoding="utf-8"?>
<album>
  <entry>
    <id>253</id>
    <title>title1</title>
  </entry>
  <entry>
    <id>254</id>
    <title>title2</title>
  </entry>
</album>
На самом деле немного сложнее, но сути это не меняет. Пробую добраться до нужного значения с помощью DOM.
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
dbfactory.setNamespaceAware(true);
DocumentBuilder domparser = dbfactory.newDocumentBuilder();
StringReader reader = new StringReader(result);
InputSource inputSource = new InputSource(reader);
Document doc = domparser.parse(inputSource);
NodeList anime = doc.getElementsByTagName("album");
Пробовала по-всякому, с кучей циклов, пробовала дебажить. Ну не получаю я то, что надо. В конечном getNodeValue, в котором должен быть id, например, я получаю null. В getNodeName я получаю имена «id» и «title» через раз, в остальных случаях там находятся «#». Я ничего не понимаю. Объясните мне на пальцах, как мне забрать id и title с каждой entry.

>В конечном getNodeValue, в котором должен быть id, например, я получаю null.

Потому что текст находится в дочерней ноде относительно ноды "id". Есть такой тип ноды - текстовая нода. У нее name - null, а value - текст.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Спасибо. На одиночном элементе вроде получилось. Но я все равно не понимаю, как мне взять именно id или title, а не только по индексу. Можете мне показать пример цикла, который бы выводил строки вида "NodeName: NoneValue" в каждой entry? :)

Dirty_Diana
() автор топика

Вам надо проверять текстовая нода или нет, как уже было сказано выше. Это можно делать с помощью: getNodeType()

Если тип equals Node.ELEMENT_NODE, то брать getNodeName(), если Node.TEXT_NODE, то getNodeValue().

В Вашем случае проще всего взять ноду, которая Вам нужна(например, getNodeName().equals("id"))) и искать по children в духе:

for(Node child = element.getFirstChild(); child != null; child = child.getNextSibling()){ ... }

rual_ilmarranen
()
Ответ на: комментарий от Dirty_Diana

Я все таки предпочитаю XPath. Меньше for-лупового быдлокода.


DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
dbfactory.setNamespaceAware(true);
DocumentBuilder domparser = dbfactory.newDocumentBuilder();
Document doc = domparser.parse(new FileInputStream("conf/bozo.xml"));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("/album/entry/id/text()");			
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
    System.out.println(nodes.item(i).getNodeValue()); 
}

Output:

253
254

Absurd ★★★
()
Ответ на: комментарий от rual_ilmarranen

>К сожалению, XPath'овые либы есть не везде, и for-луповый быдлокод единственное, что остается.

XPath входит JRE начиная с 1.5

Absurd ★★★
()

Спасибо вам за помощь, наконец-то получилось. Но код вышел ну оооооочень кривой и некрасивый. Пишу и плачу горькими слезами :(

Dirty_Diana
() автор топика
Ответ на: комментарий от Absurd

>>XPath входит JRE начиная с 1.5

В JDK тогда уж? Бтв, приходилось неоднократно работать со старыми проектами, которые тянутся еще с 1.3 и переводить на 1.4+ их никто не собирается из-за наличия, например, енумов.

А, вообще, поверьте уж унылому эмбедщику) Много где нет ни XPath'овых либ, ни даже нормальных парсеров.

rual_ilmarranen
()
Ответ на: комментарий от rual_ilmarranen

>А, вообще, поверьте уж унылому эмбедщику) Много где нет ни XPath'овых либ, ни даже нормальных парсеров.

Да вообще DOM-говно для for-луповых индусов. Лучше уж SAX если XPath-а нет.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Это уже вопрос вкуса. Опять-таки не факт, что SAX держится, а вот без DOM'а мне пока платформ не встречалось. Хотя на последнем моем проекте(эмбедщина, да) SAX был.

rual_ilmarranen
()
Ответ на: комментарий от Absurd

>Я все таки предпочитаю XPath. Меньше for-лупового быдлокода.

Да и, вообще, если Вам с сервака выдадут XML вида
<container>
  <container>
    <container/>
   </container>
</container>

Где контейнер - это нода с любой вложенностью этих самых контейнеров, описывающая виджет, потому их надо распарсить с сохранением структуры и прочей фигни, то очень бы мне хотелось посмотреть, как Вы выкрутитесь без for-лупов и рекурсий.
Хотя, вполне допускаю, что я чего-то не знаю об XPath, ибо очень редко приходилось с ним работать.


rual_ilmarranen
()
Ответ на: комментарий от rual_ilmarranen

>Где контейнер - это нода с любой вложенностью этих самых контейнеров, описывающая виджет, потому их надо распарсить с сохранением структуры и прочей фигни, то очень бы мне хотелось посмотреть, как Вы выкрутитесь без for-лупов и рекурсий.

XPath поверх узлов DOM делается. Это чисто метод навигации.

Absurd ★★★
()
Ответ на: комментарий от Absurd

>>XPath поверх узлов DOM делается. Это чисто метод навигации.

Я понимаю, признаю некую неточность с моей стороны. Распарсится всё отлично, но вот как Вы реализуете навигацию по приведенному мной XML с помощью XPath?

rual_ilmarranen
()
Ответ на: комментарий от rual_ilmarranen

Навигировать до документу ОП-а можно примерно так

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr1 = xpath.compile("/album/entry");
XPathExpression expr2 = xpath.compile("id/text()");
XPathExpression expr3 = xpath.compile("title/text()");
NodeList nodes = (NodeList) expr1.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
   Node node = nodes.item(i);
   System.out.println(expr2.evaluate(node, XPathConstants.STRING) + ":" + expr3.evaluate(node, XPathConstants.STRING));
}

Output:

253:title1 254:title2 

Absurd ★★★
()
Ответ на: комментарий от Absurd

>>Навигировать до документу ОП-а можно примерно так

Мной выше был приведен XML http://www.linux.org.ru/view-message.jsp?msgid=3923244&lastmod=1249065990...

по которому надо пройтись XPath'ом.

Если что - это реальная задача, которую нам приходилось реализовывать. Надо было по подобному XML нарисовать UI, где(если очень упростить) каждому container соответствовал аналог свингового JLabel.

rual_ilmarranen
()
Ответ на: комментарий от rual_ilmarranen

>>Навигировать до документу ОП-а можно примерно так

>Мной выше был приведен XML

Но не было указано в какой формат надо преобразовать эту структуру. Что уровень вложенности достигает трех чтоли?

Absurd ★★★
()
Ответ на: комментарий от Absurd

Уровень вложенности любой. Например, 
<container>
  <container>
    <contаiner>
      <contаiner\>
      <container>
          .....
      </container>
    <contаiner\>
    <contаiner\>
   ..
</container>

 порождает что-то в духе
JLabel.add((new JLabel()).add(new JLabel)..)

<нытик-коммент>
Я понимаю, что это извратный изврат, но заказчик где-то в Штатах решил использовать именно такой формат и изменять его не хочет никаким образом.
</нытик-коммент>

Это к чему я вообще. Я ни разу не спорю, что XPath классная штука, и, если он поддерживается и подходит для поставленной задачи - это прекрасно. Но иногда его не хватает и приходится делать рекурсии и for-loop's. 

rual_ilmarranen
()

>doc.getElementsByTagName("album");

Там нет .root или ещё какого свойства?

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.