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


Автор: check 26.1.2007, 16:32
Возникла необходимость преобразовать xml-документ в другой формат(текстовый файл с разделителями). Для обработки XML решил использовать  JAXP 1.2.  

Для того чтобы начать с ним работать нужно скомпилировать исходники и получить следующий набор JAR-файлов
Код

-  dom.jar 
-  sax.jar 
-  jaxp-api.jar 
-  xercesImpl.jar 
-  xalan.jar 
-  xsltc.jar 



Как сказано в ридми, скачал apache-ant-1.7.0, создал переменную ANT_HOME, прописал там путь к каталогу Ant,    из каталога JAXP запустил команду -ant jars 

Ответ: ant не является исполняемым файлом и т.д.


Автор: Tony 26.1.2007, 17:12
Посмотри как правельно ти написал ANT_HOME. Там должна быть папка bin. Типа: 
ANT_HOME = c:\ant
PATH = %ANT_HOME%\bin
Перегрузи компик.

Автор: LSD 26.1.2007, 17:16
Пропиши каталог %ANT_HOME%\bin в PATH.

Автор: batigoal 29.1.2007, 09:44
Цитата(check @  26.1.2007,  17:32 Найти цитируемый пост)
Возникла необходимость преобразовать xml-документ в другой формат(текстовый файл с разделителями). Для обработки XML решил использовать  JAXP 1.2.  

А почему не XSLT?

Автор: check 29.1.2007, 10:01
Как я понимаю, XSLT позволяет вывести XML в том или ином виде,  но разве он может записать текст в файл?

Автор: check 29.1.2007, 11:41
Цитата(Tony @  26.1.2007,  17:12 Найти цитируемый пост)
Посмотри как правельно ти написал ANT_HOME. Там должна быть папка bin. Типа: 
ANT_HOME = c:\ant
PATH = %ANT_HOME%\bin
Перегрузи компик. 


Цитата(LSD @  26.1.2007,  17:16 Найти цитируемый пост)
Пропиши каталог %ANT_HOME%\bin в PATH. 


Всё это сделал.   Когда выполняю команду -ant jars,   получаю ту же ошибку.
Попробовал так
Код

ant jars



Код

Buildfile: build.xml

init:

BUILD FAILED
c:\jaxp\build.xml:152:\ java.lang.NoClassDefFoundError: org/apache/commons/net/ftp/FTPClientConfig


Добавлено @ 11:45 
Но это означает что в переменных окружения все верно.

Автор: LSD 29.1.2007, 12:13
1. Проверь что в каталоге %ANT_HOME%\lib есть файл ant-commons-net.jar
2. Проверь что переменная ANT_HOME указывает именно на коневую папку ANT-а, а не на bin или еще куда.

Автор: check 29.1.2007, 12:53
Оба пункта проверил. 
ant-commons-net.jar есть.   ANT_HOME=C:\Ant.

Автор: Tony 29.1.2007, 13:34
Код

Как я понимаю, XSLT позволяет вывести XML в том или ином виде,  но разве он может записать текст в файл?

Конечно может.ХМЛ + ХСЛТ = fajl HTML

Автор: LSD 29.1.2007, 14:32
Значит тебе понадобится еще http://jakarta.apache.org/commons/net/index.html, надо будет положить файл commons-net.jar в каталог %ANT_HOME%\lib.

Только зачем он понадобился, что написано в readme по поводу сборки JAXP, он что исходники пытается из сети качать?

P.S. Ты не можешь перейти на JDK 1.5 и старше (там уже все встроено)?

Автор: check 29.1.2007, 14:56
У меня JDK 1.5.0_07.

Добавлено @ 15:00 
Цитата(Tony @  29.1.2007,  13:34 Найти цитируемый пост)
ХМЛ + ХСЛТ = fajl HTML
По моему это просто XML,  к которому применены стили XSL.

Автор: LSD 29.1.2007, 15:01
В JDK 1.5 встроен JAXP 1.3.

Автор: check 29.1.2007, 15:30
Какие классы надо импортировать для работы с SAX?  
Код

import org.xml.sax.*;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

Не один из этих классов компилятор не находит.

Автор: batigoal 29.1.2007, 16:27
Цитата(check @  29.1.2007,  15:56 Найти цитируемый пост)
По моему это просто XML,  к которому применены стили XSL.

XSLT - это язык задания преобразований XML. Поэтому сам по себе он не занимается записью в файл. Это может сделать XSLT-процессор.
А с помощью XSLT ты можешь преобразовать XML-ник в другой XML-ник, HTML, txt, PDF, fb2...

Автор: check 29.1.2007, 16:41
Цитата(batigoal @  29.1.2007,  16:27 Найти цитируемый пост)
Поэтому сам по себе он не занимается записью в файл. Это может сделать XSLT-процессор.
 Вот этот момент мне непонятен.   Как осуществить эту запись в файл?  Само по себе преобразование по-моему действительно проще всего сделать в XSLT.

Автор: LSD 29.1.2007, 17:09
Цитата(check @  29.1.2007,  15:30 Найти цитируемый пост)
Не один из этих классов компилятор не находит.

Не может этого быть, все эти классы есть в JDK 1.5 (они даже есть в JDK 1.4).

http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXPXSLT6.html

Автор: check 29.1.2007, 17:21
Цитата(check @  29.1.2007,  16:41 Найти цитируемый пост)
Вот этот момент мне непонятен.   Как осуществить эту запись в файл? 

Это кажется понял.



[

Автор: check 30.1.2007, 14:23
Решил все-таки делать через SAX.

Вот класс, который выводит названия всех тегов и заключенные в них текстовые значения
Код

import org.xml.sax.*;
import javax.xml.parsers.*;
import javax.xml.parsers.SAXParser;
import java.io.*;
import java.util.*;

public class  Transform extends HandlerBase {

//текстовые данные заключенные в соответствующие теги
  String num;  
  String  fam;
  String im;
  String ot;
  String document;
  String docSeria;
  String docNum;
  String datavd;
  String inn;

  public static void main(String fname[]) {
  
        SAXParserFactory saxFactory = SAXParserFactory.newInstance();
        saxFactory.setValidating(false);
   
        try {
            SAXParser saxParser = saxFactory.newSAXParser();
            saxParser.parse(new File(fname[0]),  new Transform());
            
        }
        catch(SAXParseException ex) { System.out.println("ParseError:" + ex.getMessage()); }
        catch(SAXException ex) { ex.printStackTrace(); } 
        catch(ParserConfigurationException ex) { ex.printStackTrace(); }
        catch(IOException ex) { ex.printStackTrace(); }
   }

  public void setDocumentLocator(Locator fname) {
        System.out.println("start  " + fname.getSystemId());
  }

 public void startDocument() throws SAXException {
    
 }

 public void startElement(String el_name, AttributeList attr) throws SAXException {
     System.out.println("element start " + el_name);
   
    if (attr != null) {
          for (int i=0; i < attr.getLength(); i++) 
                    System.out.println(attr.getName(i) + " = " + attr.getValue(i));
    } 

   //массив в который помещаются значения узлов
   String[] dataFromXML = {num, fam, im, ot, document, docSeria, docNum, datavd};

   FWriter fr = new FWriter(dataFromXML);
   fr.save();
}

 public void characters(char buf [], int offset, int len) throws SAXException {
       if (len > 0) {
            String content = new String(buf, offset, len);
            System.out.println("characters  " + content);
       }
}

}

Строковые поля объявленные в начале - это значения нескольких тегов которые, предположим , меня интересуют(на самом деле их конечно больше).


Далее я должен эти поля поместить в массив,  а массив передать в конструктор класса,   пишущего в файл.  Это конечно приблизительная схема,  имя txt-файла будет определятся именем XML-я.
Код

 //массив в который помещаются значения узлов
   String[] dataFromXML = {num, fam, im, ot, document, docSeria, docNum, datavd, inn};

   FWriter fr = new FWriter(dataFromXML);
   fr.save();

class FWriter {

    File txt;
    String[] values;
   
    FWriter(String[] values) {

         txt = new File("data.txt");
         this.values =  values;
       
    }

    public void save() {
        try
        {
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(txt)));
            for (int i=0;  i < values.length;  i++) {
                  out.print(values[i] + ", ");   
            }
            out.close();
        }
        catch(IOException ex) {};
    }
}


Вопрос в том как организовать в методе characters() присвоение текстовых значений тегов соответсвующим переменным. 
То есть если тег называется <ИНН>, берем его значение и помещаем в inn, и так далее.

Автор: batigoal 30.1.2007, 14:43
check, сделай через HashMap. Ключом будет "inn", значением - соответственно, его значение.

Автор: check 30.1.2007, 15:01
Код

 public void characters(char buf [], int offset, int len) throws SAXException {
     String content = null;
     if (len > 0) {
          content = new String(buf, offset, len);
     }
     if (element.equals("НомерВпачке")) {
           num =  content;
    }
     else if (element.equals("ИНН")) {
           inn = content;
   }
     else if (element.equals("КПП")) {
           kpp = content;
     }
     else if (element.equals("НаименованиеОрганизации")) {
           org = content;
    }
//массив в который помещаются значения узлов
   String[] dataFromXML = {num, inn,kpp,org};

   FWriter fr = new FWriter(dataFromXML);
   fr.save();
 }

Вроде бы  они и извлекаются, но в файл пишутся переводы строки через запятую.
Цитата(batigoal @  30.1.2007,  14:43 Найти цитируемый пост)
check, сделай через HashMap. Ключом будет "inn", значением - соответственно, его значение. 
Я пока через массив делаю, но это надо  ещё посмотреть по структуре, может лучше и так.

Автор: check 30.1.2007, 16:05
Цитата(check @  30.1.2007,  15:01 Найти цитируемый пост)
в файл пишутся переводы строки через запятую
Причина в том, что метод haracters()
вызывается для каждого тега и соответственно файл каждый раз перезаписывается тем что есть в массиве на данный момент.
При последнем вызове, поскольку тег не подходит ни под одно из условий, массив пустой.

Автор: LSD 30.1.2007, 17:37
Сделай запись в файл в обработчике endDocument (), и перейди на DocumentHandler.

Автор: check 30.1.2007, 17:43
Цитата(check @  30.1.2007,  16:05 Найти цитируемый пост)
При последнем вызове, поскольку тег не подходит ни под одно из условий, массив пустой.
Это конечно ерунда,  если переменная получила значение она должна сохранить его до конца.

Я вспомнил про метод endDocument().  Запись в файл я поместил туда, тобы она происходила  один раз при достижении конца документа.
Код

 public void endDocument() throws SAXException  {
     System.out.println(inn + "\n"); //пусто
     String[] dataFromXML = {num, inn,kpp,org};
     FWriter fr = new FWriter(dataFromXML);
     fr.save();
 }   


Но переменные которым в методе characters() присвоены значения: 
Код

public void characters(char buf [], int offset, int len) throws SAXException {
     String content = null;
     if (len > 0) {
          content = new String(buf, offset, len);
     }
     if (element.equals("НомерВпачке")) {
           num =  content;
    }
     else if (element.equals("ИНН")) {
           inn = content;
   }
     else if (element.equals("КПП")) {
           kpp = content;
     }
     else if (element.equals("НаименованиеОрганизации")) {
           org = content;
    }
//массив в который помещаются значения узлов
   String[] dataFromXML = {num, inn,kpp,org};

   FWriter fr = new FWriter(dataFromXML);
   fr.save();
 }

в endDocument() пусты.  Соответственно  массив тоже пуст,  а в файл пишутся квадраты через запятую  smile 

Провёл такой эксперимент.  При объявлении присвоил переменным начальные значения
Код

    String num= "1";  
    String  fam= "1";
    String im= "1";
    String ot= "1";
    String document= "1";
    String docSeria= "1";
    String docNum= "1";
    String datavd= "1";
    String inn= "1";
    String kpp= "1";
    String org= "1";
Переменные не затронутые в методе characters() в endDocument() имеют значение "1",  остальные - пусто.
При этом если их вывести в самом методе  characters(), они имеют нормальные значения взятые из xml-я.

Добавлено @ 17:45 
Цитата(LSD @  30.1.2007,  17:37 Найти цитируемый пост)
Сделай запись в файл в обработчике endDocument (), и перейди на DocumentHandler. 

Первое уже сделал.  Что такое DocumentHandler?

Автор: LSD 30.1.2007, 17:51
Вместо:
Код
public class Transform extends HandlerBase

используй:
Код
public class  Transform implements DocumentHandler


По поводу первой проблемы, посмотри под отладчиком метод characters() вообще вызывается.

Автор: check 30.1.2007, 18:01
Пришлось сделать так
Код

public class  Transform extends HandlerBase implements DocumentHandler

В интерфейсе DocumentHandler нет метода parse().
Но ничего не изменилось.
characters() вызывается
Код

 public void characters(char buf [], int offset, int len) throws SAXException {
       String content = null;
       if (len > 0) {
            content = new String(buf, offset, len);
            System.out.println("characters  " + content);
       }
    if (element.equals("НомерВпачке")) {
           num =  content;
          System.out.println(num + "\n");
     }
     else if (element.equals("ИНН")) {
           inn = content;
           System.out.println(inn + "\n");
    }
     else if (element.equals("КПП")) {
           kpp = content;
           System.out.println(kpp + "\n");
    }
     else if (element.equals("НаименованиеОрганизации")) {
           org = content;
           System.out.println(org + "\n");
    }  

}
выводит то что нужно.

Автор: check 31.1.2007, 10:34
Как сделать чтобы в файл добавлялись строки не пеезаписывая файл?
(да, плоховато я ещё знаю Java=))

Это нужно в любом случае, но я ещё чувствую,  что это  ключ к решению проблемы.
Похоже на то, что метод characters() вызывается в любом случае более одного раза для каждого тега и при последнем вызове
считывает то ли null, то ли перевод строки. 

Автор: check 31.1.2007, 11:06
Нашел
Код

FileWriter(txt, true)



Цитата(check @  31.1.2007,  10:34 Найти цитируемый пост)
Похоже на то, что метод characters() вызывается в любом случае более одного раза для каждого тега и при последнем вызове
считывает то ли null, то ли перевод строки. 

Так и есть. Вот что пишется для в файл из такого тега: <СистемныйНомерМассиваПоручений>060-009-2006-00005</СистемныйНомерМассиваПоручений> 

Тег встречается в документе два раза

Код

060-009-2006-00005, 
     , 
     , 060-009-2006-00015, 
     , 
     , 

То есть получается - текст, потом два перевода строки.

Автор: check 31.1.2007, 16:48
Цитата(batigoal @  30.1.2007,  14:43 Найти цитируемый пост)
check, сделай через HashMap. Ключом будет "inn", значением - соответственно, его значение


Последовал совету - создал типизированный HashMap
Код

HashMap<String, String>


Код теперь выглядит гораздо приятнее, хотя переводы строки в файл по-прежнему пишутся.

Вопрос решён, большое спасибо!

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