Я не уверен, какой уровень вас беспокоит.
Прежде всего вы будете перебирать все символы XML.
Лично я бы использовал StringTokenizer. Я знаю, что он немного устарел, но вы можете легко разобрать его по двум интересующим вас символам в угловых скобках, и вы можете настроить его так, чтобы он возвращал "Жетоны".
Таким образом, каждый полученный вами токен будет иметь левый угол, прямой угол или какую-либо строку без углов.
В XML угол не вкладывается, что на самом деле экономит вам немного времени.
так скажем, ваш XML выглядел следующим образом (За пределами блоков кода я конвертирую угловые скобки в парены, потому что мне не хочется печатать все дерьмо с амперсандом, всем, кому это неудобно, предлагается отредактировать мой пост и исправить его). он):
<tag var="meh">between</tag>
Ваш первый токен - «<», затем «tag var =» meh », затем«> », затем« между », затем« <», затем« / tag », затем«> »
Пока все хорошо.
Вы должны знать, находитесь ли вы в угловых скобках или снаружи, чтобы знать, что делать со строками, так что следите за этим как булево. Поскольку вложенности нет, достаточно одного логического значения.
Вам также нужно знать об уровнях вложенности ваших тегов. Это должно автоматически заставить ваш мозг высвечивать слово «стек». Стеки - это способ реализации вложенности, точка.
Итак, ваш процесс, прочитайте токен. Если это «<», установите внутреннее логическое значение на «истина» и продолжить, если это «>», установите логическое значение на «ложь» и продолжайте. Ушли эти двое с дороги! Ты наполовину готов!
Далее, если вы находитесь внутри, я бы создал объект со следующими свойствами:
String tagName
HashMap<String, String> attributes
// Why the heck do angle-brackets correctly display here SO?!?
String value
и поместите его в свой стек. (Обратите внимание, что LinkedList имеет API стека)
Таким образом, вы должны сохранить имя в «tagName» и переменные в HashMap и продолжить. Если бы это был я, у этого маленького класса был бы конструктор, который бы брал строку, а строка, которую он брал, была бы строкой между угловыми скобками. Он проанализирует саму строку и сохранит tagName и атрибуты перед возвратом.
Если вы сделали это, то ваш цикл, вы просто говорите, что вы «inside = true» и значение не является угловой скобкой (вы знаете, что это не так, эти случаи уже были удалены!), Тогда просто:
push(new XMLObject(token));
(упс, если «токен» в этот момент начинается с «/», вы должны сделать что-то другое, продолжайте читать).
Очень лаконично и читабельно, нет?
Наконец, остался только один случай, когда вы находитесь снаружи и ваша строка является токеном. В этом случае вы знаете, что самой последней записью стека был XMLObject, который был заполнен за исключением «значения». Значение должно быть токеном, который у вас есть прямо сейчас.
Готово, кроме печати.
О, я забыл, когда вы нажимаете на закрывающий тег, вам нужно вытолкнуть значение из стека и распечатать его (нажмите для открытия тега, нажмите для закрытия тега)
Вы можете получить свой уровень отступа, проверив размер стека (stack.size () должен определить, сколько вкладок нужно распечатать).
Если вы действительно хотите разделить обязанности, я бы хотел, чтобы XMLObject реализовал toString, которая форматировала данные так, как вы хотели их печатать, тогда, когда вы достигнете конечного тега, все, что вам нужно сделать, это:
Pop the XMLObject.
Print out stack.size() tabs (use print not println!)
Print XMLObject.toString();
На самом деле это весь ваш проект (кроме трудоемкого фактического кодирования).
Научитесь проходить процесс анализа, изучая ваши данные и разрабатывая простую программу, подобную этой, должна быстро стать второй натурой.
Удачи вам в карьере!
Это немного усложнилось, поэтому я составил этот список возможностей. Итерируйте его для каждого токена и обрабатывайте каждый случай. Я почти уверен, что это покрывает все возможности, и если вы включите проверку ошибок, где я указал, это будет на самом деле качество производства (я думаю).
Примечание: на самом деле вы не можете сделать это как дело. Рассмотрим заявления if / if else.
case token = "<" //note, if already "inside", this is an error
if(inside) throw exception // Indicates < tagname <
inside=true;
case token = ">"
if(!inside) throw exception // Indicates > text or not >
inside=false;
case inside = false
stack.peek().setValue(token)
case inside (inside = true)
sub-case token startsWith "!-- & endsWith "--"
comment, ignore
sub-case token startsWith "/" and endsWith "/" and is more than 1 char long
create the object, then act as though you found a close tag
sub-case token = ""
(throw exception/print error/bail! // inside must have a tag!)
sub-case token.startsWtih("/")
create & push
sub-case token doesn't .startWith "/"
sub-sub-case length=1 (just the slash, lazy close tag)
pop & print
sub-sub-case length > 1
print an error unless (stack.peek().getTagName().equals(tagWithoutSlash))
pop & print
Вот и все. Я думаю, что каждый из этих случаев был одной строкой, может быть, 2 или 3, если вы не вкладываете вещи, такие как stack.push (новый XMLObject (токен)).
Я бы не стал так много рассказывать, но все сложнее, чем я думал, поскольку я включаю все проверки ошибок и прочее.
Я старался избегать настоящей Java везде, где это возможно, поэтому используйте свой собственный стиль! Класс XMLObject, как описано, действительно хорошая идея. Привыкайте создавать новые классы везде, где это возможно (я буквально никогда не видел кода с большим количеством классов).
Это слишком большая помощь, но это так весело, что я могу написать парсер XML только для этого.