Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > как проверить заголовок XML?


Автор: stan90 28.11.2009, 17:55
у меня есть синтаксический анализатор 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);
}
}

Автор: LSD 29.11.2009, 12:34
А зачем писать свой велосипед? Почему бы не использовать стандартный SAX парсер?

Автор: stan90 29.11.2009, 16:04
у меня задание такое))

Автор: stan90 30.11.2009, 18:43
товарищи очень нужна ваша помощь!!)

Автор: ivanovpv 30.11.2009, 19:36
Таких задание-творцов надо фтопку... Проще же применить SAX парсер ловить исключения и выкидывать сообщения парсера...

Если ближе к телу, то парсер проще сделать рекурсивным примерно таким:
1) Распознавание заголовка
2) Чтение первого тега
   а) Если есть вложенный тег - начинаем рекурсию (см. п.1)
3) Чтение закрывающего тега

Отдельно обработки собственно тега (выделение параметров), убирание пробелов, комментариев


Автор: stan90 30.11.2009, 22:14
ну вот я сделал для открывающихся и закрывающихся тегов..а как для комментариев,загаловка и параметров сделать я не знаю..у меня не получается)

Автор: rimidal 1.12.2009, 09:53
Есть такая штука как БНФ и РБНФ. Это что касается теории парсеров. К этой теории также относятся конечные автоматы и регулярные выражения.

Есть еще генераторы парсеров (еще их называют компиляторы компиляторов). Я например использовал CocoR. Для него есть плагин под eclipse. Но есть и множество других генераторов. Их можно найти например здесь: http://www.java-sources.org/open-source/parser-generators

Автор: stan90 1.12.2009, 16:42
так мне не нужны никакие генераторы))

мне нужно чтобы программа которую я начал писать проверяла правильно ли составлен XML документ или нет)

Автор: rimidal 1.12.2009, 23:32
Цитата

так мне не нужны никакие генераторы))

мне нужно чтобы программа которую я начал писать проверяла правильно ли составлен XML документ или нет)


Генератор сгенерирует вам исходный код тех классов которые и должны выполнять эту задачу.
На примере CocoR :
1. Надо описать парсер на БНФ (в вашем случае это БНФ XML-я - его кстати можно найти в интернете).
2. По полученому БНФ будут сгенерированы исходники двух классов которые после компиляции будут производить разбор выражений (в вашем случае XML файлы).

Правда здесь есть один момент - надо знать синтаксис описания БНФ для конкретного генератора. Как правило к генераторам прилагаются примеры - может и повезет с XML-ем.

Автор: LSD 2.12.2009, 15:58
Заголовок XML, это processing instruction и в принципе она может встречаться в любом месте XML документа (вернее заголовок может быть, только в начале, а вот другие processing instruction в любом месте).

В твоем случае, тебе надо сделать парсинг помимо тегов, еще и processing instructions, комментариев, DTD, CDATA. Создай отдельный класс, который будет заниматься разбивкой входного текста на теги: открывающий тег, закрывающий тег, тело тега, комментарий, DTD, CDATA и processing instruction.

Автор: rimidal 2.12.2009, 16:30
EBNF для XML: 
http://www.jelks.nu/XML/xmlebnf.html

Ох и не простая эта задача, даже с генератором.

Автор: stan90 3.12.2009, 01:43
а ни у кого нет  может быть кода какого нить парсера для проверки xml,я бы по анологии разобрался бы?)

Автор: rimidal 3.12.2009, 08:58
Так ведь SAX открытая библиотека, с исходниками. Можно посмотреть там.

http://sourceforge.net/projects/sax/files/

Автор: stan90 4.12.2009, 08:53
не то..(

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)