Java-задача с XML

Всем привет!

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


Задание: реализовать функцию со следующей сигнатурой:

Collection<String> folderNames(String xml, char startingLetter)

Она должна принимать на вход строку xml, содержащую XML-структуру, подобную этой:


<?xml version="1.0" encoding="UTF-8"?>

<folder name="c">

<folder name="program files">

<folder name="uninstall information" />

</folder>

<folder name="users" />

</folder>


а также букву startingLetter


В качестве возвращаемого значения должна быть коллекция значений всех аттрибутов name, каждая из которых начинается с буквы startingLetter.


Например, для XML выше, функция должна вернуть коллекцию с "uninstall information" и "users" (порядок не важен).


Решения добавляйте в комментариях (желательно, ссылки на github/pastebin), постараюсь првоести их код-ревью, а через некоторое время выложу свое решение.


Ну и по традиции, кот, из одного известного стикерпака ^_^

Java-задача с XML

Правила сообщества

Прошу воздержаться от взаимных оскорблений.

Больше позитива, ведь программирование - это весело)

2
Автор поста оценил этот комментарий

например, используем xpath
подробности тут - https://gist.github.com/averkhoglyad/ec2641bfde7c983125007e0...)

шаблон запроса - "//folder[starts-with(@nаme,'%s')]/@nаme" (где %s заменяется на startingLetter)

после чего просто выгребаем все ноды:

XPathFactory.newInstance().newXPath()

.compile(String.format(tpl, startingLetter))

.evaluate(document, XPathConstants.NODESET);


и собираем результат:

int nodesLength = nodes.getLength();

Collection<String> result = new ArrayList<>(nodesLength);

for (int i = 0; i < nodesLength; i++) {

result.add(nodes.item(i).getNodeValue());

}

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Выглядит верно, но я бы вместо цикла и мутаций коллекции использовал Stream API

показать ответы
1
Автор поста оценил этот комментарий

Забыл дописать, что для XML выше, функция должна вернуть коллекцию с "uninstall information" и "users", для переданной буквы u

1
Автор поста оценил этот комментарий

Думаю, стоит уточнить каким хочется видеть решение, через регулярные выражения, через готовые парсеры или используя только циклы да сравнение.

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

На ваше усмотрение, есть много вариантов решения

0
Автор поста оценил этот комментарий

1. Будет использован ArrayList без указания размера (т.к. стрим его не имеет и может вообще быть бесконечным), а значит по мере заполнения массив придётся его пересоздавать (см. сорцы)

2. Накладные расходы конечно же будут ещё и потому что создаётся и используется больше объектов, обёрток и т.п.

3. Предложенный способ со стримами явно не придаёт коду читаемости, просто дублирует перебор индексов, ещё и зачем-то переводит примитивы в обёртки (хотя метод NodeList::item ожидает именно примитив int и будет преобразован обратно). Немного более элегантным решением было бы создать стрим нод (для этого надо сделать Iterator для перебора нод в нод-листе + на сколько я помню, ещё и Iterable, который его вернёт)

4. Не хочу jaxb и рекурсию, ничего сверх красивого не получится, а кода будет больше, ещё и xml мапить в объекты. Правда вот тут Stream API будет уже удобно использовать.

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

1,2. Лень заходить в сорцы :) Этот момент прописан в доке? Если нет, то далеко не факт, что это работает именно так. Порой код дает просто общее понимание, как работает функциональность, а JIT может все перевернуть там, и дока + сигнатуры публичных методов являются единственными инвариантами. Кроме того мы можем дописать parallel() и кто знает, может этот способ будет даже быстрее.

3. Говорю, не открывал ide, может boxed действительно не нужен и зайдут примитивы

4. Думаю завтра выложу этот вариант)


11 файлов посмотрел, интересные подходы, спасибо!

1
Автор поста оценил этот комментарий

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

Да и вообще, Stream API надо использовать там, где в нём есть необходимость, т.е. реально поток данных (хотя я конечно тоже его люблю использовать где только можно).

Так что притензия отклоняется)))


А вообще, можно даже сделать адаптер NodeList к интерфейсу Collection и обернуть его. Тогда даже перегонять ничего не надо будет (да, его мне тоже лень писать).

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Нет, преобразование в лист произойдет единожды, накладных расходов не будет

Будет что-то вроде этого (не проверял в IDE, насколько помню, напрямую из нод стрим не получить): return IntStream.range(0, nodes.getLength()).boxed().map(nodes::item).map(Item::getNodeValue).collect(toList());

Если хотите, можете еще сделать решение с помощью JAXB и продумать красивый рекурсивный алгоритм для получившейся коллекции, соответствующей XML-файлу.

показать ответы

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества