у меня есть синтаксический анализатор XML файла,но у меня получилось сделать только чтобы он проверял открывающиеся и закрывающиеся теги и показывал номер позиции где ошибка... подскажите пожалуйста как сделать проверку для заголовка?
| Код |
import java.io.*;
import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern;
public class XMLParser { //Для дальнейшего анализа ошибок предусмотрим защищенное поле curPos, //которое будет содержать номер символа, на котором остановилось чтение выражения. //Соответственно, при вызове метода parse() необходимо обнулить это поле. protected int curPos = 0; protected BufferedReader inputText; protected Stack<XMLTag> stack = new Stack<XMLTag>(); private String errorMessage; private Object oldCurrPos; public boolean parse(BufferedReader inputText) throws IOException { //является единственным публичным методом, //т.е. на данный момент представляет интерфейс класса. //На вход ему пользователь должен передать объект класса потокового ввода текстовых данных //с буферизацией BufferedReader, который записывается в защищенное поле inputText this.inputText = inputText; curPos = 0; boolean result = parseHeader(); //метод parse() передает управление методу parseHeader() //для анализа заголовка выражения return result ? parseTag() : false; } /*protected Boolean parseNameTag(String tag) { if (tag.equals("")) return Boolean.valueOf(true); Pattern pattern = Pattern.compile("[a-zA-Z\\u005F]{1}[a-zA-Z\\d\\u002D\\u002E\\u005F]*"); Matcher matcher = pattern.matcher(tag); if (matcher.matches()) return Boolean.valueOf(true);
this.errorMessage = "Неправильное имя идентификатора"; this.curPos = Integer.valueOf(((Integer) this.oldCurrPos).intValue() + 1); return Boolean.valueOf(false); }*/
protected boolean parseHeader() { return true; }
protected boolean parseTag() throws IOException { skipWS(); // пропустим пробельные символы boolean result = parseOTag(); // первым должен идти открывающий тег if (!result) // если результат отрицательный return false; // возвращаем ложь do { // в цикле skipToDelimeters("<"); // пропускаем все символы до левой угловой // скобки. Этом может быть полезный текст - // в будущем будем его использоват if (testStart("</")) // проверим, не закрывающий ли это тег return parseCTag(); // и если да, то вернем результат его // анализа — завершаем обработку данного // тега if (testStart("<")) { // если это был не закрывающий тег, проверим, // не похоже ли это на вложенный открывающий // тег if (!parseTag()) // и проанализиуем его (рекурсивный вызов), но // если результат отрицательный, return false; // вернем ложь } else // а если это был не закрывающий и не открывающий тег, то мы // дошли до конца потока ввода return false; // в этом случае возвращаем ложь } while (true); // цикл не имеет условия выхода — возврат осуществляется // из тела цикла }
protected boolean parseOTag() throws IOException { skipWS(); if (!testStart("<")) return false; if (testStart("</")) return false; int c = inputText.read(); curPos++; XMLTag tag = new XMLTag(skipToDelimeters("> \n\t")); stack.push(tag); if (!testStart(">")) if (!parseParams(tag)) return false; c = inputText.read(); if (c != 13) curPos++; if (c == '>') return true; else return false; }
protected boolean parseParams(XMLTag tag) throws IOException { //Прежде чем модифицировать метод обработки открывающего тега //напишем «заглушку» вспомогательного метода, //обрабатывающего параметры тега skipToDelimeters(">"); return true; }
protected boolean parseCTag() throws IOException { skipWS(); if (!testStart("</")) return false; inputText.skip(2); curPos+=2; XMLTag tag = stack.pop(); if (!tag.name.equals(skipToDelimeters(">"))) return false; int c = inputText.read(); if (c != 13) curPos++; if (c == '>') return true; else return false; }
public boolean testStart(String str) throws IOException { //Метод testStart() принимает на входе строку и проверяет, //совпадает ли она с началом выражения считая с текущей позиции int len = str.length(); // запишем длину переданной на входе строки в // переменную len char[] cbuf = new char[len]; // создадим массив символов длины len inputText.mark(len); // «Отметим» место в потоке ввода (в выражении). // Метод reset() позволит к нему вернуться, если // мы считаем не более, чем len символов len = inputText.read(cbuf, 0, len); // прочитаем в массив cbuf с текущей // (нулевой) позиции len символов и // запишем в len количество // фактически прочитанных символов inputText.reset(); // вернем поток ввода в исходное состояние if (len == -1) // если ничего не удалось прочитать, вернем ложь return false; String sbuf = new String(cbuf, 0, len); // на основе массива cbuf // создадим строку (из его // первых len символов) if (sbuf.compareToIgnoreCase(str) == 0) // если строка на входе равна // строке sbuf, вернем истину return true; else // иначе, вернем ложь return false; }
protected void skipWS() throws IOException { //Метод skipWS() пропускает все идущие подряд пробельные символы в выражении //с текущей позиции int c; // локальная переменная для последовательного чтения символов do { inputText.mark(1); // отметим положение в потоке ввода, чтобы иметь // возможность вернуться на 1 символ c = inputText.read(); // прочитаем символ из потока if (c != 13) // увеличим счетчик количества считанных символов. При // переводе строки в Windows генерируется два // символа с кодами 13 (0xD, возврат каретки) и 10 // (0xA, перевод строки), в Linux — только 10 (0xA). // Т.е. условие введено для корректного подсчета // символов перевода строки в Windows, при // сохранении совместимости с Linux curPos++; } while (Character.isWhitespace(c)); // продолжим, пока встречаются // пробельные символы. Для того, // чтобы определить что // прочитанный символ является // пробельным, воспользуемся // статическим методом // isWihtespace() класса // Character. inputText.reset(); // вернем поток в исходное состояние (на 1 символ // назад), т.к. последний символ не был пробельным curPos--; // и исключим этот символ из счетчика }
protected String skipToDelimeters(String delimeters) throws IOException { //Метод skipToDelimeters() считывает все символы в выражении с текущей позиции, //пока не встретит один из символов, перечисленных в строке delimeters int c; // локальная переменная для последовательного чтения символов StringBuffer sb = new StringBuffer(); // буфер для хранения // последовательности считанных // символов do { // в цикле inputText.mark(1);// отметим положение в потоке ввода, чтобы иметь // возможность вернуться на 1 символ c = inputText.read(); // прочитаем символ из потока if (delimeters.indexOf(c) == -1 && c != -1) { // если символ с не // встречается в // строке delimeters // и при этом он был // успешно прочитан // (c != -1), sb.append((char) c); // то добавляем его в буфер sb if (c != 13) curPos++; // и увеличиваем счетчик прочитанных символов (по // условию (c != 13) см. метод skipWS()) } else break; // иначе выйдем из цикла } while (true); inputText.reset(); // последний символ присутствовал в строке // delimeters, возвратим поток в исходное положение return sb.toString().trim(); // вернем в качестве результата считанные в // буфер sb символы, преобразовав его к // стоке и обрезав с обеих сторон // пробельные символы }
public int getCurPos() { //Метод getCurPos() расширяет интерфейс класса XMLParser, //позволяя пользователю узнать положение в потоке ввода (после вызова метода parse()). return curPos; }
public static void main(String[] args) throws IOException { BufferedReader isr = new BufferedReader(new InputStreamReader(//Объект isr класса BufferedReader //создается для чтения из файла test.txt // (System.in)); new FileInputStream("test.txt"), "cp1251")); XMLParser xp = new XMLParser();//Далее создается объект класса XMLParser //и на экран выводятся результат анализа текста //(true/false, т.е. успешно/неуспешно) и порядковый номер символа, //на котором остановилась обработка. System.out.println(xp.parse(isr)); System.out.println(xp.curPos); } }
|
|