Программе должно быть разрешено читать из XML-файла с использованием выражений XPath. Я уже начал проект с использованием JDOM2, переключение на другой API нежелательно. Сложность в том, что программа не знает заранее, если она должна читать элемент или атрибут. Предоставляет ли API какую-либо функцию для получения содержимого (строки), просто предоставляя ему выражение XPath? Из того, что я знаю о XPath в JDOM2, он использует объекты разных типов для оценки выражений XPath, указывающих на атрибуты или элементы. Меня интересует только контент атрибута/элемента, на который указывает выражение XPath.Java XML JDOM2 XPath - чтение текстового значения из атрибута XML и элемента с использованием выражения XPath
Вот пример XML-файл:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
Это то, что моя программа выглядит следующим образом:
package exampleprojectgroup;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.sax.XMLReaders;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
public class ElementAttribute2String
{
ElementAttribute2String()
{
run();
}
public void run()
{
final String PATH_TO_FILE = "c:\\readme.xml";
/* It is essential that the program has to work with a variable amount of XPath expressions. */
LinkedList<String> xPathExpressions = new LinkedList<>();
/* Simulate user input.
* First XPath expression points to attribute,
* second one points to element.
* Many more expressions follow in a real situation.
*/
xPathExpressions.add("/bookstore/book/@category");
xPathExpressions.add("/bookstore/book/price");
/* One list should be sufficient to store the result. */
List<Element> elementsResult = null;
List<Attribute> attributesResult = null;
List<Object> objectsResult = null;
try
{
SAXBuilder saxBuilder = new SAXBuilder(XMLReaders.NONVALIDATING);
Document document = saxBuilder.build(PATH_TO_FILE);
XPathFactory xPathFactory = XPathFactory.instance();
int i = 0;
for (String string : xPathExpressions)
{
/* Works only for elements, uncomment to give it a try. */
// XPathExpression<Element> xPathToElement = xPathFactory.compile(xPathExpressions.get(i), Filters.element());
// elementsResult = xPathToElement.evaluate(document);
// for (Element element : elementsResult)
// {
// System.out.println("Content of " + string + ": " + element.getText());
// }
/* Works only for attributes, uncomment to give it a try. */
// XPathExpression<Attribute> xPathToAttribute = xPathFactory.compile(xPathExpressions.get(i), Filters.attribute());
// attributesResult = xPathToAttribute.evaluate(document);
// for (Attribute attribute : attributesResult)
// {
// System.out.println("Content of " + string + ": " + attribute.getValue());
// }
/* I want to receive the content of the XPath expression as a string
* without having to know if it is an attribute or element beforehand.
*/
XPathExpression<Object> xPathExpression = xPathFactory.compile(xPathExpressions.get(i));
objectsResult = xPathExpression.evaluate(document);
for (Object object : objectsResult)
{
if (object instanceof Attribute)
{
System.out.println("Content of " + string + ": " + ((Attribute)object).getValue());
}
else if (object instanceof Element)
{
System.out.println("Content of " + string + ": " + ((Element)object).getText());
}
}
i++;
}
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
catch (JDOMException jdomException)
{
jdomException.printStackTrace();
}
}
}
Другая мысль заключается в поиске символа «@» в выражении XPath, чтобы определить, указывает ли он на атрибут или элемент. Это дает мне желаемый результат, хотя я бы хотел, чтобы было более элегантное решение. Предоставляет ли JDOM2 API что-нибудь полезное для этой проблемы? Может ли код быть переработан в соответствии с моими требованиями?
Спасибо заранее!
Является ли 'Attribute' в JDOM2 подклассом' Content'? http://www.jdom.org/docs/apidocs/org/jdom2/Attribute.html не показывает, что поэтому я смущен, почему ваш ответ, кажется, предполагает, что 'XPathExpression xPathExpression = xPathFactory.compile (xPathExpressions.get (i), Filters.content()) 'обрабатывает элементы и атрибуты. –
Ahhh .... дерьмо. Я забыл, что Атрибуты не довольны. Он имеет метод getValue(), и я предположил. Позвольте мне подумать об этом на мгновение. – rolfl
Я не могу придумать, как лучше обрабатывать неоднозначные результаты XPath, чем проверять его. JDOM, возможно, упростил ситуацию, если оба узла Element и Attribute имеют общий предок, но есть и другие причины, по которым это невозможно. Я отредактировал ответ, чтобы рекомендовать извлечение функции, чтобы аккумулировать код, а не изменять основной механизм, описанный OP. – rolfl