ФИАС: различия между версиями

Материал из GIS-Lab
Перейти к навигации Перейти к поиску
(xml2sql)
Строка 5: Строка 5:


= Загрузка данных =
= Загрузка данных =
== PostgreSQL ==
 
Рассмотрим процесс импорта данных из файлов XML в реляционную базу данных на примере PostgreSQL. Для других БД (MySQL, SQL Server, Oracle и т.п.) процедура потребует незначительной доработки.
 
=== Структура таблиц ===
=== Структура таблиц ===
Формат XML. XSD схемы выгрузки БД ФИАС в формате XML.
 
XSL Transformation:
На сайте ФИАС представлены схемы XSD, описывающие структуру данных. Для преобразования схема в формат SQL (CREATE TABLE...) применим XSL Transformation (XSLT). В зависимости от БД может потребоваться изменить типы данных колонок.


<div class="toccolours mw-collapsible">
<div class="toccolours mw-collapsible">
Строка 22: Строка 24:
<xsl:variable name="filename" select="lower-case(tokenize(tokenize(base-uri(.), '/')[last()],'\.')[1])" />
<xsl:variable name="filename" select="lower-case(tokenize(tokenize(base-uri(.), '/')[last()],'\.')[1])" />


DROP TABLE IF EXISTS <xsl:value-of select="$filename"/>;
CREATE TABLE <xsl:value-of select="$filename"/> (
CREATE TABLE <xsl:value-of select="$filename"/> (
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<a"<xsl:value-of select="@name" />" </a>
    <xsl:text</xsl:text><xsl:value-of select="@name"/><xsl:text> </xsl:text>
<xsl:choose>
<xsl:choose>
<!-- тип данных -->
<!-- тип данных -->
Строка 38: Строка 41:


<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
<a>COMMENT ON COLUMN <xsl:value-of select="$filename"/>."<xsl:value-of select="@name" />" IS </a>
<a>COMMENT ON COLUMN <xsl:value-of select="$filename"/>.<xsl:value-of select="@name" /> IS </a>
<xsl:choose>
<xsl:choose>
    <!-- Часть комментариев слишком длинные, обрезаем лишние строки -->
    <!-- Часть комментариев слишком длинная, обрезаем лишние строки -->
<xsl:when test="contains(xs:annotation/xs:documentation,'&#xa;')">
<xsl:when test="contains(xs:annotation/xs:documentation,'&#xa;')">
<a>'<xsl:value-of select="substring-before(xs:annotation/xs:documentation,'&#xa;')"/>'</a>
<a>'<xsl:value-of select="substring-before(xs:annotation/xs:documentation,'&#xa;')"/>'</a>
Строка 55: Строка 58:
</div>
</div>


Схема подходит для всех таблиц ФИАС. Для работы требуется парсер, поддерживающий XSLT 2.0. Например, для Windows - [http://sourceforge.net/projects/saxon/ Saxon XSLT Processor] (MPL). Тогда обработка файлов может принять вид (для версии .NET):
Схема подходит для всех таблиц ФИАС. Для работы требуется парсер, поддерживающий XSLT 2.0. Например, для Windows - [http://sourceforge.net/projects/saxon/ Saxon XSLT Processor] (MPL). Тогда обработка файлов принимает вид (для версии .NET):


<div class="toccolours mw-collapsible">
<div class="toccolours mw-collapsible">
Строка 76: Строка 79:


=== Импорт данных ===
=== Импорт данных ===
Для работы с большими файлами XML предпочтительнее применять потоковые парсеры. Ниже приводится скрипт ETL Scriptella, использующий java-парсер SAX. Он подходит для любой реляционной БД, для которой есть java-драйвер.
<syntaxhighlight lang="java">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE etl SYSTEM "http://scriptella.javaforge.com/dtd/etl.dtd">
<etl>
    <description>
        Создание таблицы из файла '../sql' и загрузка данных из файла '../xml'
    </description>
    <properties>
        <include href="db.properties"/>
    </properties>
    <connection id="in" driver="janino"/>
    <connection id="out" driver="${driver}" url="${url}" user="${user}" password="${password}">
        autocommit.size=100
    </connection>
    <connection id="err" driver="text" url="errors.log"/>
    <script connection-id="out">
        <include href="../sql/###TABLE###.sql" encoding="utf-8"/>
    </script>
    <query connection-id="in">
        import javax.xml.parsers.SAXParser;
        import javax.xml.parsers.SAXParserFactory;
        import org.xml.sax.Attributes;
        import org.xml.sax.SAXException;
        import org.xml.sax.helpers.DefaultHandler;
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        DefaultHandler handler = new DefaultHandler() {
            boolean isObject = false;
            int recordCnt = 0;
            public void startElement(String uri, String localName,String qName, Attributes attr) throws SAXException {
                if (qName.equalsIgnoreCase("Object")) {
                    String names = "";
                    String values = "";
                   
                    int attrCnt = attr.getLength();
                    for (int i=0; i &lt; attrCnt; i++) {
                        names += attr.getQName(i) + ",";
                        values += "'" + attr.getValue(i) + "',";
                    }
                    names = names.substring(0, names.length()-1);
                    values = values.substring(0, values.length()-1);
                    set("sql_names", names);
                    set("sql_values", values);
                    <script connection-id="out">
                        INSERT INTO ###TABLE### ($sql_names) VALUES ($sql_values);
                    </script>
                    next();
                    recordCnt++;
                    System.out.print("\rprocessed: " + recordCnt);
                }
            }
        };
        System.out.println("\n\n\nConverting...");
        saxParser.parse("../xml/###TABLE###.xml", handler);
    </query>
</etl>
</syntaxhighlight>


== MySQL ==
== MySQL ==

Версия от 20:02, 6 января 2013

Эта страница является черновиком статьи.


Введение

Наследие КЛАДР...

Загрузка данных

Рассмотрим процесс импорта данных из файлов XML в реляционную базу данных на примере PostgreSQL. Для других БД (MySQL, SQL Server, Oracle и т.п.) процедура потребует незначительной доработки.

Структура таблиц

На сайте ФИАС представлены схемы XSD, описывающие структуру данных. Для преобразования схема в формат SQL (CREATE TABLE...) применим XSL Transformation (XSLT). В зависимости от БД может потребоваться изменить типы данных колонок.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text" encoding="UTF-8" indent="no"/>

<xsl:template match="/">
<xsl:variable name="filename" select="lower-case(tokenize(tokenize(base-uri(.), '/')[last()],'\.')[1])" />

DROP TABLE IF EXISTS <xsl:value-of select="$filename"/>;
CREATE TABLE <xsl:value-of select="$filename"/> (
<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
    <xsl:text>  </xsl:text><xsl:value-of select="@name"/><xsl:text> </xsl:text>
	<xsl:choose>
		<!-- тип данных -->
		<xsl:when test="xs:simpleType/xs:restriction/@base='xs:integer'">integer</xsl:when>
		<xsl:when test="xs:simpleType/xs:restriction/@base='xs:byte'">integer</xsl:when>
		<xsl:when test="xs:simpleType/xs:restriction/@base='xs:string'">text</xsl:when>
		<xsl:when test="@type='xs:date'">date</xsl:when>
	</xsl:choose>
	<xsl:if test="@use='required'"> NOT NULL</xsl:if>
	<xsl:if test="position()!=last()">,&#xa;</xsl:if>
</xsl:for-each>
);

<xsl:for-each select="/xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[1]/xs:complexType[1]/xs:attribute" >
	<a>COMMENT ON COLUMN <xsl:value-of select="$filename"/>.<xsl:value-of select="@name" /> IS </a>
	<xsl:choose>
    	<!-- Часть комментариев слишком длинная, обрезаем лишние строки -->
		<xsl:when test="contains(xs:annotation/xs:documentation,'&#xa;')">
			<a>'<xsl:value-of select="substring-before(xs:annotation/xs:documentation,'&#xa;')"/>'</a>
		</xsl:when>
		<xsl:otherwise>'<xsl:value-of select="xs:annotation/xs:documentation"/>'</xsl:otherwise>
	</xsl:choose>
	<xsl:text>;&#xa;</xsl:text>
</xsl:for-each>
	
</xsl:template>
</xsl:stylesheet>

Схема подходит для всех таблиц ФИАС. Для работы требуется парсер, поддерживающий XSLT 2.0. Например, для Windows - Saxon XSLT Processor (MPL). Тогда обработка файлов принимает вид (для версии .NET):

@echo off
SET PATH=%PATH%;d:\Program Files\Saxonica\SaxonHE9.4N\bin

for %%f in (*.xsd) do (
    Transform ^
        -xsl:xsd2db.xslt ^
        -s:%%f ^
        -o:sql\%%~nf.sql
)

Далее полученные файлы SQL желательно откорректировать, чтобы явно назначить ключи (primary keys).

//// Ссылка на готовые файлы

Импорт данных

Для работы с большими файлами XML предпочтительнее применять потоковые парсеры. Ниже приводится скрипт ETL Scriptella, использующий java-парсер SAX. Он подходит для любой реляционной БД, для которой есть java-драйвер.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE etl SYSTEM "http://scriptella.javaforge.com/dtd/etl.dtd">
<etl>
    <description>
        Создание таблицы из файла '../sql' и загрузка данных из файла '../xml'
    </description>
    <properties>
        <include href="db.properties"/>
    </properties>

    <connection id="in" driver="janino"/>
    <connection id="out" driver="${driver}" url="${url}" user="${user}" password="${password}">
        autocommit.size=100
    </connection>
    <connection id="err" driver="text" url="errors.log"/>

    <script connection-id="out">
        <include href="../sql/###TABLE###.sql" encoding="utf-8"/>
    </script>

    <query connection-id="in">
        import javax.xml.parsers.SAXParser;
        import javax.xml.parsers.SAXParserFactory;
        import org.xml.sax.Attributes;
        import org.xml.sax.SAXException;
        import org.xml.sax.helpers.DefaultHandler;

        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();

        DefaultHandler handler = new DefaultHandler() {
            boolean isObject = false;
            int recordCnt = 0;

            public void startElement(String uri, String localName,String qName, Attributes attr) throws SAXException {
                if (qName.equalsIgnoreCase("Object")) {
                    String names = "";
                    String values = "";
                    
                    int attrCnt = attr.getLength();
                    for (int i=0; i &lt; attrCnt; i++) {
                        names += attr.getQName(i) + ",";
                        values += "'" + attr.getValue(i) + "',";
                    }

                    names = names.substring(0, names.length()-1);
                    values = values.substring(0, values.length()-1);
                    set("sql_names", names);
                    set("sql_values", values);
                    <script connection-id="out">
                        INSERT INTO ###TABLE### ($sql_names) VALUES ($sql_values);
                    </script>
                    next();

                    recordCnt++;
                    System.out.print("\rprocessed: " + recordCnt);
                }
            }
        };

        System.out.println("\n\n\nConverting...");
        saxParser.parse("../xml/###TABLE###.xml", handler);
    </query>
</etl>

MySQL

Готовые данные http://basicdata.ru/

Классификаторы России (rus-ref)

Структура данных ФИАС (описание таблиц)