Парсинг XML по атрибутам

В примере про количество рабочих дней с учетом праздников мы парсили HTML код по атрибутам. Для получения содержимого необходимых тэгов использовали методы getElementsByAttributeValue и getElementsByClass сторонней библиотеки JSOUP.

Для парсинга XML текста , в отличие от HTML, традиционно применяют библиотеки, которые входят в стандартные поставки JDK. Для чтения, как правило, применяют DOM. Но столкнувшись с необходимостью чтения XML документа по значению атрибутов не обнаружил в этом пакете аналогов таких удобных методов, которыми я пользовался при парсинге HTML. Если с getElementsByClass еще это объяснимо, все таки class очень распространенный атрибут в HTML который не часто встретишь в XML, то getElementsByAttributeValue действительно не хватает.

Итак задачка. У нас есть великолепный XML файл, в котором все записано только с помощью одного тэга – parameter. Отличить что есть что можно только по значению атрибута «name» которое бывает или «variable» или «calculator».

<parameter type="Map">
<parameter name="variable">var1</parameter>
<parameter name="calculator">calc1</parameter>
<parameter name="variable">var2</parameter>
<parameter name="calculator">calc2</parameter>
</parameter>

Для начала стандартное создание объекта тип Document из XML файла. Считываем все тэги parameter и помещаем их в NodeLest. Получается несколько избыточно, поскольку видим, что первый тэг с type=”Map” структурно включает 4 других тэга parameter, но ничего лучше не придумал.

DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = f.newDocumentBuilder();
Document doc = builder.parse(new File("src/file.xml"));
doc.normalizeDocument();
NodeList nNodes = doc.getElementsByTagName("parameter");

Теперь нужно пробежаться по ним. Запускаем цикл в котором вытаскиваем одну ноду, считываем все аттрибуты в переменную NameNodeMap attributes. Вытаскиваем значением атрибута “name” и кладем в ноду attr. Далее идет блок оператора if, которым мы проверяем значение атрибута и если оно нас устривает, то вытаскиваем текст тэга из ноды методом getTextContent.

for (int j = 0; j < nNodes.getLength(); j++){
Node nNode = nNodes.item(j);
NamedNodeMap attributes = nNode.getAttributes();
Node attr = attributes.getNamedItem("name");
if (attr != null) {
if (attr.getTextContent().equals("variable")) {
String s = nNode.getTextContent();
System.out.println(j + ", " + s);
} else if (attr.getTextContent().equals("calculator")) {
String s = nNode.getTextContent();
System.out.println(j + ", " + s);
}
}
}

Output:
1, var1
2, calc1
3, var2
4, calc2

Программа будет работать для любого количества вложений. Например, вот что получится если программе скормить следующий XML:

<parameter type="Map">
<parameter type="Maps">
<parameter type="MoreMaps">
<parameter name="variable">var1</parameter>
<parameter name="calculator">calc1</parameter>
</parameter>
</parameter>
</parameter>

Ouput:
3, var1
4, calc1