Обработка иерархического XML-документа с помощью XPATH в Java. Эффективность?
Варианты этого вопроса уже задавались здесь несколько раз, но мой вопрос больше относится к общей эффективности использования XPATH в Java.
Моя задача: взять статьи в Википедии о географических местоположениях и создать из них иерархическую структуру данных.
Я уже получил XML-версии вики-страниц и переформатировал их в соответствии со схемой, которая имеет интуитивный смысл. Я также сделал серию очень простых классов, представляющих различные уровни административной иерархии, например:
public class Province implements java.io.Serializable {
private ArrayList<City> cities = new ArrayList<City>();
private String hanzi;
private String pinyin;
public Province(String hanzi, String pinyin) {
this.hanzi = hanzi;
this.pinyin = pinyin;
}
А также метод добавления городов, некоторые методы получения и установки, а также метод toString().
Вот пример типа XML-файла, с которым я имею дело:
<mediawiki>
<page>
<title>Tianjin</title>
<revision>
<id>2064019</id>
<text xml:space="preserve">
<province>
<hanzi>天津</hanzi>
<pinyin>Tianjin</pinyin>
<Level2>
<hanzi>和平</hanzi>
<pinyin>Heping</pinyin>
<zip>300000</zip>
</Level2>
<Level2>
<hanzi>河东</hanzi>
<pinyin>Hedong</pinyin>
<zip>300000</zip>
</Level2>
</province>
</text>
</revision>
</page>
...
</mediawiki>
У меня по сути есть функциональная настройка на данный момент, но код является чрезвычайно повторяющимся и не учитывает внутреннюю иерархическую природу географических данных. В идеале я мог бы остановиться на определенном уровне (скажем, "сосредоточиться" на конкретной провинции) и относиться к вещам только в относительных терминах, начиная с этого момента, чтобы минимизировать количество попыток сканирования всего документа. В качестве примера (обратите внимание, я использую абстракцию поверх традиционной установки Document, но методы, приведенные ниже, почти точно соответствуют традиционным методам):
XPathReader reader = new XPathReader("sourceXML\\Provinces.xml");
String expression = "/mediawiki/page";
NodeList allProvinces = (NodeList)reader.read(expression, XPathConstants.NODESET);
for(int i=0; i < allProvinces.getLength(); i++) {
expression = "/mediawiki/page[" + i + "]/revision/text/province/hanzi";
String hanzi = reader.read(expression, XPathConstants.STRING).toString();
expression = "/mediawiki/page[" + i + "]/revision/text/province/pinyin";
String pinyin = reader.read(expression, XPathConstants.STRING).toString();
Province currProv = new Province(hanzi, pinyin);
expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2";
NodeList level2 = (NodeList)reader.read(expression, XPathConstants.NODESET);
for(int j=1; j < level2.getLength(); j++) {
expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2[" + j + "]/hanzi";
String hanzi2 = reader.read(expression, XPathConstants.STRING).toString();
expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2[" + j + "]/pinyin";
String pinyin2 = reader.read(expression, XPathConstants.STRING).toString();
City currCity = new City(hanzi2, pinyin2);
currProv.add(currCity);
...
}
}
Откровенно говоря, это кажется глупым. Я не принимаю во внимание тот факт, что все в этих строках идентично, когда я поднимаюсь на уровень, который меня интересует. Я не ссылаюсь ни на какой относительный путь, и всякий раз, когда я пересекаю часть документа, я фактически пересекаю всю вещь. Было бы здорово, если бы я мог на время заблокировать остальную часть исходного XML-документа и сосредоточиться только на своей провинции, ссылаясь на все в дальнейшем с относительной точки зрения.
Особо следует отметить, насколько дорого это стоит за абстракцией "читать":
xPath.compile(expression);
String result = xPathExpression.evaluate (xmlDocument, returnType);
Я по существу перекомпилирую идентичный шаблон с немного другим окончанием? Как насчет загрузки интересующей части, а затем обращения к ее дочерним элементам с помощью чего-то вроде "currProv/hanzi"?
Я рассмотрел другие методы синтаксического анализа XML, и "Digester", кажется, делает что-то похожее на то, что я хочу http://commons.apache.org/digester/core.html, но у меня уже есть почти все в этом XPATH реализация.
У меня есть ноющее подозрение, что решение этой проблемы очень простое... но я не могу понять это решение. Во всяком случае, я благодарю вас за ваше время!
1 ответ
Относительные вложенные XPath - это путь.
Я возглавляю реализацию EclipseLink JAXB (MOXy), и мы предлагаем эту возможность через аннотацию @XmlPath. Если у вас уже есть XPath, это было бы относительно простым отображением.
Для получения дополнительной информации см.: