Разбор Java XML - PullRequest
       25

Разбор Java XML

1 голос
/ 21 сентября 2009

Я мог бы использовать некоторые рекомендации по следующей проблеме. Вся часть «Использование библиотек XML запрещено» заставляет меня задуматься. Спасибо!

Создайте Java-программу, которая принимает XML в качестве входных данных, анализирует входные данные и записывает в консоль все имена элементов с отступами их уровень вложенности. Вы должны обрабатывать атрибуты XML, но вы не делаете должны отображать или иным образом интерпретировать их. Там нет необходимости обрабатывать CDATA или любые инструкции по обработке XML. Нет использования XML библиотеки разрешены.

Ответы [ 4 ]

2 голосов
/ 21 сентября 2009

Я не уверен, какой уровень вас беспокоит.

Прежде всего вы будете перебирать все символы 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 только для этого.

1 голос
/ 21 сентября 2009

Просто просмотрите XML-файл символ за символом и сделайте то, что вам нужно сделать.

  1. Настройка некоторой переменной состояния (со значениями, такими как ожидание открытия тега, чтение имени элемента, ожидание имени атрибута, чтение значения атрибута, чтение содержимого элемента - ожидание закрытия тега и т. Д.).

  2. Настройте счетчик глубины (потому что он вам нужен для красивой печати).

  3. Используйте переменную состояния и текущий символ, чтобы решить, как изменить состояние или добавить новый символ к тому, что вы уже прочитали.

  4. Предположим, что ваш XML правильно сформирован.

Ваша реальная задача намного проще, чем звучит «XML-парсер».

1 голос
/ 21 сентября 2009

Сложные случаи, о которых следует знать:

  • комментариев, например <!-- this is a comment-->
  • пустых тегов (/> окончание тега, например <element foo='1' bar='2' baz='3' />)
1 голос
/ 21 сентября 2009

Id использует Test Driven Development здесь

Я бы написал тесты вроде

assertEquals ("test", parse (""));

assertEquals ("test", parse (""));

assertEquals ("test \ n \ tfun", parse (""));

и т.д.. и заставь их всех пройти.

не забудьте обработать угловые случаи и плохой xml.

разбор можно сделать:

1) с помощью String.indexOf найти первый (<) и последний (>) элемент xml в цикле и обработать то, что внутри. использование рекурсии даст вам лучшую оценку.

2) вы также можете использовать String.split. Вы можете разделить первый и последний элемент XML или использовать регулярные выражения, чтобы получить то, что находится внутри элементов XML.

2a - это самое простое, 2b может быть самым быстрым для написания, если вы знаете регулярное выражение, но 1 лучше, потому что оно быстрее (вы можете его не видеть, но звучит быстрее), и многие учителя заботятся только о производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...