Spec-Zone .ru
спецификации, руководства, описания, API
След: API Java для XML, Обрабатывающего (JAXP)
Урок: Преобразования Расширяемого языка таблиц стилей
Генерирование XML от Произвольной Структуры данных
Домашняя страница > API Java для XML, Обрабатывающего (JAXP) > Преобразования Расширяемого языка таблиц стилей

Генерирование XML от Произвольной Структуры данных

Этот раздел использует XSLT, чтобы преобразовать произвольную структуру данных в XML.

Вот схема процесса:

  1. Измените существующую программу, которая читает данные, чтобы заставить это генерировать события SAX. (Является ли та программа реальным синтаксическим анализатором, или просто фильтр данных некоторого вида не важен в настоящий момент).

  2. Используйте SAX "синтаксический анализатор", чтобы создать SAXSource для преобразования.

  3. Используйте тот же самый объект StreamResult как создающийся в последнем осуществлении, чтобы вывести на экран результаты. (Но отметьте, что Вы могли так же, как легко создать объект DOMResult создать ДОМА в памяти).

  4. Соедините источник проводом к результату, используя объект преобразователя сделать преобразование.

Для стартеров Вы нуждаетесь в наборе данных, который Вы хотите преобразовать и программа, способная к чтению данных. Следующие два раздела создают простой файл данных и программу, которая читает его.

Создание Простого Файла

Этот пример использует набор данных для адресной книги, PersonalAddressBook.ldif. Если Вы так уже не сделали, download the XSLT examples и разархивируйте их в install-dir/jaxp-1_4_2-release-date/samples каталог. Файл, показанный здесь, был произведен, создавая новую адресную книгу в Средстве рассылки Netscape, давая его некоторые фиктивные данные (одна карта адреса), и затем экспортируя его в Формате обмена данными LDAP (LDIF) формат. Это содержало в каталоге xslt/data после того, как Вы разархивировали примеры XSLT.

Следующие данные показывают запись адресной книги, которая создавалась.

Изобразите Запись Адресной книги

Снимок карты контактной информации Thunderbird Mozilla.

Экспорт адресной книги производит файл как один показанный затем. Части файла, о котором мы заботимся, показывают полужирным.

dn: cn=Fred Flintstone,mail=fred@barneys.house
modifytimestamp: 20010409210816Z
cn: Fred Flintstone
xmozillanickname: Fred
mail: Fred@barneys.house
xmozillausehtmlmail: TRUE
givenname: Fred
sn: Flintstone
telephonenumber: 999-Quarry
homephone: 999-BedrockLane
facsimiletelephonenumber: 888-Squawk
pagerphone: 777-pager
cellphone: 555-cell
xmozillaanyphone: 999-Quarry
objectclass: top
objectclass: person

Отметьте, что каждая строка файла содержит имя переменной, двоеточие, и пространство, сопровождаемое значением для переменной. Переменная sn содержит фамилию человека (фамилия), и переменный cn содержит поле DisplayName от записи адресной книги.

Создание Простого Синтаксического анализатора

Следующий шаг должен создать программу, которая анализирует данные.


Отметьте - код, обсужденный в этом разделе, находится в AddressBookReader01.java, который находится в каталоге xslt после того, как Вы разархивировали XSLT examples в install-dir/jaxp-1_4_2-release-date/samples каталог.


Текст для программы показывают затем. Это - чрезвычайно простая программа, которая даже не циклично выполняется для многократных записей, потому что, в конце концов, это - только демонстрационный пример.

import java.io.*; 

public class AddressBookReader01 { 

    public static void main(String argv[]) {
        // Check the arguments
        if (argv.length != 1) {
            System.err.println("Usage: java AddressBookReader01 filename");
            System.exit (1);
        }

        String filename = argv[0];
        File f = new File(filename);
        AddressBookReader01 reader = new AddressBookReader01();
        reader.parse(f);
    }

    // Parse the input file
    public void parse(File f) {
        try {
            // Get an efficient reader for the file
            FileReader r = new FileReader(f);
            BufferedReader br = new BufferedReader(r);

            // Read the file and display its contents.
            String line = br.readLine();
            while (null != (line = br.readLine())) {
                if (line.startsWith("xmozillanickname: "))
                    break;
            }

            output("nickname", "xmozillanickname", line);
            line = br.readLine();
            output("email",  "mail", line);

            line = br.readLine();
            output("html", "xmozillausehtmlmail", line);

            line = br.readLine();
            output("firstname","givenname", line);

            line = br.readLine();
            output("lastname", "sn", line);

            line = br.readLine();
            output("work", "telephonenumber", line);

            line = br.readLine();
            output("home", "homephone", line);

            line = br.readLine();
            output("fax", "facsimiletelephonenumber", line);

            line = br.readLine();
            output("pager", "pagerphone", line);

            line = br.readLine();
            output("cell", "cellphone", line);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Эта программа содержит три метода:

main

Метод main получает имя файла из командной строки, создает экземпляр синтаксического анализатора, и устанавливает это, чтобы работать, анализируя файл. Этот метод исчезнет, когда мы преобразуем программу в синтаксический анализатор SAX. (Который является одной причиной помещения кода парсинга в отдельный метод).

parse

Этот метод работает на объекте File, отправленном этому основной подпрограммой. Как можно видеть, это очень прямо. Единственная концессия эффективности является использованием BufferedReader, который может стать важным, когда Вы начинаете работать на больших файлах.

output

Выходной метод содержит логику для структуры строки. Требуется три параметра. Первый параметр дает методу имя к дисплею, таким образом, это может вывести html как имя переменной вместо xmozillausehtmlmail. Второй параметр дает имя переменной, сохраненное в файле (xmozillausehtmlmail). Третий параметр дает строку, содержащую данные. Подпрограмма тогда снимает изоляцию с имени переменной от запуска строки и выводит требуемое имя плюс данные.

Выполнение Выборки AddressBookReader01

  1. Переместитесь к каталогу samples.
    % cd install-dir/jaxp-1_4_2-release-date/samples.
    
  2. Download the XSLT examples by clicking this link и разархивируйте их в install-dir/jaxp-1_4_2-release-date/samples каталог.
  3. Переместитесь к каталогу xslt.
    cd xslt
    
  4. Скомпилируйте выборку AddressBookReader01.

    Введите следующую команду:

    % javac AddressBookReader01.java
    
  5. Выполните выборку AddressBookReader01 на файле данных.

    В случае ниже, AddressBookReader01 выполняется на файле, который PersonalAddressBook.ldif, показанный выше, нашел в каталоге xslt/data после того, как Вы разархивировали демонстрационный пакет.

    % java AddressBookReader01 data/PersonalAddressBook.ldif
    

    Вы будете видеть следующий вывод:

    nickname: Fred
    email: Fred@barneys.house
    html: TRUE
    firstname: Fred
    lastname: Flintstone
    work: 999-Quarry
    home: 999-BedrockLane
    fax: 888-Squawk
    pager: 777-pager
    cell: 555-cell
    

    Это немного больше читаемо чем файл, показанный в Создании Простого Файла.

Создание Синтаксического анализатора, который Генерирует События SAX

Этот раздел шоу, как заставить синтаксический анализатор генерировать события SAX, так, чтобы можно было использовать это в качестве основания для объекта SAXSource в XSLT, преобразовывает.


Отметьте - код, обсужденный в этом разделе, находится в AddressBookReader02.java, который находится в каталоге xslt после того, как Вы разархивировали XSLT examples в install-dir/jaxp-1_4_2-release-date/samples каталог. AddressBookReader02.java адаптируется от AddressBookReader01.java, таким образом, только различия в коде между этими двумя примерами будут обсуждены здесь.


AddressBookReader02 требует следующих выделенных классов, которые не использовались в AddressBookReader01.

import java.io.*; 

import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;

Приложение также расширяет XmlReader. Это изменение преобразовывает приложение в синтаксический анализатор, который генерирует соответствующие события SAX.

public class AddressBookReader02 implements XMLReader { /* ... */ }

В отличие от выборки AddressBookReader01, у этого приложения нет метода main.

Следующие глобальные переменные будут использоваться позже в этом разделе:

public class AddressBookReader02 implements XMLReader {
    ContentHandler handler;

    String nsu = "";  
    Attributes atts = new AttributesImpl();
    String rootElement = "addressbook";

    String indent = "\n ";

    // ...
}

ContentHandler SAX является объектом, который генерирует события SAX синтаксическим анализатором. Чтобы подать заявку в XmlReader, приложение определяет метод setContentHandler. Переменная обработчика будет содержать ссылку на объект, который отправляется, когда setContentHandler вызывается.

Когда синтаксический анализатор генерирует события элемента SAX, он должен будет предоставить пространство имен и информацию атрибута. Поскольку это - простое приложение, оно определяет нулевые значения для обоих из тех.

Приложение также определяет корневой элемент для структуры данных (addressbook) и устанавливает строку отступа, чтобы улучшить удобочитаемость вывода.

Кроме того метод синтаксического анализа изменяется так, чтобы он взял InputSource (а не File) как параметр и учел исключения, которые он может генерировать:

public void parse(InputSource input) throws IOException, SAXException

Теперь, вместо того, чтобы создать новый экземпляр FileReader, как был сделан в AddressBookReader01, читатель инкапсулируется объектом InputSource:

try {
    java.io.Reader r = input.getCharacterStream();
    BufferedReader Br = new BufferedReader(r);
    // ...
}

Отметьте - следующие шоу раздела, как создать входной исходный объект и что вставляется, это, фактически, будет буферизованный читатель. Но AddressBookReader мог использоваться кем-то еще, где-нибудь по линии. Этот шаг удостоверяется, что обработка будет эффективна, независимо от читателя, которого Вам дают.


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

public void parse(InputSource input) {
    try {
        // ...
        String line = br.readLine();
        while (null != (line = br.readLine())) {
            if (line.startsWith("xmozillanickname: ")) 
                break;
        }

        if (handler == null) {
            throw new SAXException("No content handler");
        }

        handler.startDocument(); 
        handler.startElement(nsu, rootElement, rootElement, atts);

        output("nickname", "xmozillanickname", line);
        // ...
        output("cell", "cellphone", line);

        handler.ignorableWhitespace("\n".toCharArray(), 
            0,  // start index
            1   // length
        ); 
        handler.endElement(nsu, rootElement, rootElement);
        handler.endDocument(); 
    }
    catch (Exception e) {
        // ...
    }
}

Здесь, проверки приложения, чтобы удостовериться, что синтаксический анализатор должным образом конфигурируется с ContentHandler. (Для этого приложения мы не заботимся ни о чем больше). Это тогда генерирует события для запуска документа и корневого элемента, и заканчивается, отправляя событие конца за корневым элементом и событие конца для документа.

Два элемента примечательны в этой точке:

Теперь, когда события SAX сгенерированы для документа и корневого элемента, следующий шаг должен изменить выходной метод, чтобы генерировать соответствующие события элемента для каждого элемента данных. Удаление звонка в System.out.println(name + ": " + text) и добавление следующего выделенного кода достигают этого:

void output(String name, String prefix, String line) 
    throws SAXException {

    int startIndex = 
    prefix.length() + 2;   // 2=length of ": "
    String text = line.substring(startIndex);

    int textLength = line.length() - startIndex;
    handler.ignorableWhitespace (indent.toCharArray(), 
        0,    // start index
        indent.length()
    );
    handler.startElement(nsu, name, name /*"qName"*/, atts);
    handler.characters(line.toCharArray(), 
        startIndex,
        textLength;
    );
    handler.endElement(nsu, name, name);
}

Поскольку методы ContentHandler могут отослать назад SAXExceptions к синтаксическому анализатору, синтаксический анализатор должен быть подготовлен иметь дело с ними. В этом случае ни один не ожидается, таким образом, приложению просто позволят перестать работать, если кто-либо происходит.

Длина данных тогда вычисляется, снова генерируя некоторый игнорируемый пробел для удобочитаемости. В этом случае есть только один уровень данных, таким образом, мы можем использовать строку фиксированного отступа. (Если бы данные были более структурированы, то мы должны были бы вычислить сколько пространства, чтобы сделать отступ, в зависимости от вложения данных).


Отметьте - строка отступа не имеет никакого значения к данным, но сделает вывод намного легче читать. Без той строки все элементы были бы связаны вплотную:

<addressbook>
<nickname>Fred</nickname>
<email>...

Затем, следующий метод конфигурирует синтаксический анализатор с ContentHandler, который должен получить события, которые это генерирует:

void output(String name, String prefix, String line)
    throws SAXException {
    //  ...
}

// Allow an application to register a content event handler.
public void setContentHandler(ContentHandler handler) {
    this.handler = handler;
}  

// Return the current content handler.
public ContentHandler getContentHandler() {
    return this.handler;
}

Несколько других методов должны быть реализованы, чтобы удовлетворить интерфейс XmlReader. С целью этого осуществления нулевые методы сгенерированы для всех них. Производственное приложение, однако, потребовало бы, чтобы методы обработчика ошибок были реализованы, чтобы произвести более устойчивое приложение. Для этого примера, тем не менее, следующий код генерирует нулевые методы для них:

// Allow an application to register an error event handler.
public void setErrorHandler(ErrorHandler handler) { } 

// Return the current error handler.
public ErrorHandler getErrorHandler() { 
    return null; 
}

Затем следующий код генерирует нулевые методы для остатка от интерфейса XmlReader. (Большинство из них значимо для реального синтаксического анализатора SAX, но имеет небольшое опирание на приложение преобразования данных как этот).

// Parse an XML document from a system identifier (URI).
public void parse(String systemId) throws IOException, SAXException 
{ } 

// Return the current DTD handler.
public DTDHandler getDTDHandler() { return null; } 

// Return the current entity resolver.
public EntityResolver getEntityResolver() { return null; } 

// Allow an application to register an entity resolver.
public void setEntityResolver(EntityResolver resolver) { } 

// Allow an application to register a DTD event handler.
public void setDTDHandler(DTDHandler handler) { } 

// Look up the value of a property.
public Object getProperty(String name) { return null; } 

// Set the value of a property.
public void setProperty(String name, Object value) { }  

// Set the state of a feature.
public void setFeature(String name, boolean value) { } 

// Look up the value of a feature.
public boolean getFeature(String name) { return false; }

У Вас теперь есть синтаксический анализатор, который можно использовать, чтобы генерировать события SAX. В следующем разделе Вы будете использовать это, чтобы создать исходный объект SAX, который позволит Вам преобразовывать данные в XML.

Используя Синтаксический анализатор как SAXSource

Учитывая синтаксический анализатор SAX, чтобы использовать в качестве источника события, можно создать преобразователь, чтобы привести к результату. В этом разделе TransformerApp будет обновлен, чтобы привести к потоковому выходному результату, хотя это могло так же, как легко привести к результату ДОМА.


Отметьте - Примечание: код, обсужденный в этом разделе, находится в TransformationApp03.java, который находится в каталоге xslt после того, как Вы разархивировали XSLT examples в install-dir/jaxp-1_4_2-release-date/samples каталог.


Чтобы запуститься с, TransformationApp03 отличается от TransformationApp02 в классах, которые это должно импортировать, чтобы создать объект SAXSource. Эти классы показывают выделенные ниже. Классы ДОМА больше не необходимы в этой точке, так были отброшены, хотя оставление внутри их не делает ничего плохого.

import org.xml.sax.SAXException; 
import org.xml.sax.SAXParseException; 
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;

import javax.xml.transform.sax.SAXSource; 
import javax.xml.transform.stream.StreamResult;

Затем, вместо того, чтобы создать экземпляр ДОМА DocumentBuilderFactory, приложение создает синтаксический анализатор SAX, который является экземпляром AddressBookReader:

public class TransformationApp03 {
    static Document document;  
    public static void main(String argv[]) {
        // ...
        // Create the sax "parser".
        AddressBookReader saxReader = new AddressBookReader();

        try {
            File f = new File(argv[0]);
            // ...
        }
        // ...
    }
}

Затем, следующий выделенный код создает объект SAXSource

// Use a Transformer for output
// ...
Transformer transformer = tFactory.newTransformer();

// Use the parser as a SAX source for input
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
InputSource inputSource = new InputSource(br);
SAXSource source = new SAXSource(saxReader, inputSource);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);

Здесь, TransformationApp03 создает буферизованного читателя (как отмечалось ранее) и инкапсулирует это во входном исходном объекте. Это тогда создает объект SAXSource, передавая это читатель и объект InputSource, и передачи это к преобразователю.

Когда приложение работает, преобразователь конфигурирует себя как ContentHandler для синтаксического анализатора SAX (AddressBookReader) и говорит синтаксическому анализатору работать на объекте inputSource. События, сгенерированные синтаксическим анализатором тогда, идут в преобразователь, который делает соответствующую вещь и передает данные на объект результата.

Наконец, TransformationApp03 не генерирует исключения, таким образом, код обработки исключений, замеченный в TransformationApp02, больше не присутствует.

Выполнение Выборки TransformationApp03

  1. Переместитесь к каталогу samples.
    % cd install-dir/jaxp-1_4_2-release-date/samples.
    
  2. Download the XSLT examples by clicking this link и разархивируйте их в install-dir/jaxp-1_4_2-release-date/samples каталог.
  3. Переместитесь к каталогу xslt.
    cd xslt
    
  4. Скомпилируйте выборку TransformationApp03.

    Введите следующую команду:

    % javac TransformationApp03.java
    
  5. Выполните выборку TransformationApp03 на файле данных, который Вы хотите преобразовать в XML.

    В случае ниже, TransformationApp03 выполняется на файле PersonalAddressBook.ldif, найденном в каталоге xslt/data после того, как Вы разархивировали демонстрационный пакет.

    % java TransformationApp03 
      data/PersonalAddressBook.ldif
    

    Вы будете видеть следующий вывод:

    <?xml version="1.0" encoding="UTF-8"?>
    <addressbook>
        <nickname>Fred</nickname>
        <email>Fred@barneys.house</email>
        <html>TRUE</html>
        <firstname>Fred</firstname>
        <lastname>Flintstone</lastname>
        <work>999-Quarry</work>
        <home>999-BedrockLane</home>
        <fax>888-Squawk</fax>
        <pager>777-pager</pager>
        <cell>555-cell</cell>
    </addressbook>
    

    Как можно видеть, файл формата LDIF, PersonalAddressBook был преобразован в XML!


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Выписывание ДОМА как XML-файл
Следующая страница: Преобразование Данных XML с XSLT