一度、ミンスクの番地と家を見つける必要がありました。 どこにも完全なデータがなく、新しい道路や家が表示されたらどうするかを知ったときの失望を想像してください。
OpenStreetMapがオープンソースと絶え間ないアップデートを思いついたのはここです。 問題は、カードが最大2 GBのボリュームを持つxmlドキュメントであり、家に関する情報が次の形式で表示されることです。
<way id="25324320" > <nd ref="275904968"/> <nd ref="275904882"/> <nd ref="275904881"/> <nd ref="275904969"/> <nd ref="275904968"/> <tag k="addr:housenumber" v="17"/> <tag k="addr:postcode" v="220013"/> <tag k="addr:street" v=" "/> <tag k="building" v="yes"/> </way>
データが順序付けられ、文字列として表示されない場合、1.5 GBのデータの処理が簡単になります。 そこで、データをデータベースに変換することにしました。 それは言われています-選択された作業ツールとして、完了しました:Eclipse(Java SE)と紳士のデンバーのセット。
サイレント理論
すでに述べたように、このファイルはxmlドキュメントであり、オブジェクトのポイント(
node )、ライン(
way )、リレーション(
relation )が順番に記述されています。 各オブジェクトには、プロパティを説明するユーティリティ属性を設定できます。 概略的に、これは次のように表現できます。
ノードがポイントです。 オブジェクトの座標を格納する基本要素:緯度、経度(
lat 、
lon )。 各ポイントには独自の一意の
idがあり、
id ウェイまたは
リレーションとの一致が可能です。 XML表記では、このタイプのオブジェクトは次のようになります。
<node id="1877995696" lat="53.9216820" lon="27.5883786"/>
方法はラインです。 基本要素は、ポイントのコレクションを記述し、
idパラメーターは1つだけです。
ポイントのコレクションは、単一の
ref属性を持つ
ndタグによって記述されます
。refは、
ノード要素の
idへの参照です。
XML表記では、このタイプのオブジェクトは次のようになります。
<way id="83643843"> <nd ref="1270318960"/> <nd ref="974055589"/> <nd ref="974055636"/> <nd ref="974055581"/> <nd ref="974055604"/> </way>
関係は関係です。 オブジェクトのコレクションを記述する基本要素には、
idパラメーターが1つしかありません。 オブジェクトのコレクションは、
メンバータグによって記述されます。
メンバータグは、3つの属性で構成されます
。type-オブジェクトのタイプ、
ref-オブジェクトの
IDへのリンク、
role-ロールのパラメーター、オブジェクト間の関係を記述します。
オブジェクトを記述するために、
Tagがあります。これは、
キー (
key )、
v値 (
value )の2つの属性で構成されてい
ます 。 このタグには、オブジェクトに関するすべての情報が含まれます。 詳細は
こちらをご覧ください 。
問題の解決策を4つの部分に分けました。
1. プログラムの視覚化2. データをSQLにインポートする3. データ処理4. XMLファイルの解析。コード自体は
github.comで見ることができ、それ以上読むことはできません!
プログラムの視覚化。
視覚化には、
Swingライブラリーを使用しました。 メイン画面は、入力フィールド、ラベル、2つのボタン、ダウンロードバー、およびメッセージボックスで構成されています。
DB URLは次の形式の特別な文字列です:
jdbc:subprotocol:subname 、
ここで、
サブプロトコルはドライバーの名前または接続メカニズムの名前(
mysql )です。
subnameは、ホスト、ポート、データベース名(
// localhost / )を示す文字列です。
私たちの場合:
jdbc:mysql:// localhost /ユーザー -データベースユーザーの入力フィールド。
パスワード -データベースのパスワードを入力するフィールド。
DB名 -書き込み用に作成またはマウントされるデータベースの名前。
FilePath-データを取得するファイルの名前。
接続 -データベース接続を確認します
開始 -インポートの開始。
[
スタート ]ボタンは最初はアクティブ化されておらず、データベースへの接続が成功した後にアクティブ化されます。
ウィンドウの外観。

コード
public class Window extends Thread { private JFrame window; private JTextField userValue; private JTextField passValue; private JTextField dbNameValue; private TextArea textArea; private JButton btnConnected; private JButton btnExport; private JTextField filePathValue; private JTextField urlValue; private JProgressBar progressBar; public Window() { initialize(); } @Override public void run() { } private void initialize() { window = new JFrame(); window.setTitle("OSMtoMySQL"); window.setResizable(false); window.setBounds(100, 100, 420, 450); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.getContentPane().setLayout(null); JLabel dbUrl = new JLabel("DB URL"); dbUrl.setBounds(10, 29, 100, 14); window.getContentPane().add(dbUrl); urlValue = new JTextField(); urlValue.setText("jdbc:mysql://localhost/"); urlValue.setBounds(120, 26, 203, 20); window.getContentPane().add(urlValue); urlValue.setColumns(10); JLabel user = new JLabel("User"); user.setBounds(10, 54, 100, 14); window.getContentPane().add(user); userValue = new JTextField(); userValue.setText("root"); userValue.setBounds(120, 51, 203, 20); window.getContentPane().add(userValue); userValue.setColumns(10); JLabel pass = new JLabel("Password"); pass.setBounds(10, 79, 100, 14); window.getContentPane().add(pass); passValue = new JTextField(); passValue.setBounds(120, 76, 203, 20); window.getContentPane().add(passValue); passValue.setColumns(10); JLabel dbName = new JLabel("DB Name"); dbName.setBounds(10, 104, 100, 14); window.getContentPane().add(dbName); dbNameValue = new JTextField(); dbNameValue.setText("Belarus"); dbNameValue.setBounds(120, 101, 203, 20); window.getContentPane().add(dbNameValue); dbNameValue.setColumns(10); btnConnected = new JButton("Connect"); btnConnected.setBounds(120, 159, 89, 23); window.getContentPane().add(btnConnected); btnExport = new JButton("Start"); btnExport.setBounds(234, 159, 89, 23); btnExport.setEnabled(false); window.getContentPane().add(btnExport); textArea = new TextArea(); textArea.setEditable(false); textArea.setBounds(10, 237, 394, 175); window.getContentPane().add(textArea); JLabel filePath = new JLabel("FilePath"); filePath.setBounds(10, 129, 46, 14); window.getContentPane().add(filePath); filePathValue = new JTextField(); filePathValue.setText("BY.osm"); filePathValue.setColumns(10); filePathValue.setBounds(120, 126, 203, 20); window.getContentPane().add(filePathValue); progressBar = new JProgressBar(); progressBar.setMaximum(1000); progressBar.setBounds(10, 202, 394, 20); progressBar.setStringPainted(true); window.getContentPane().add(progressBar); } public void addLog(String str) { Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); this.textArea.append(sdf.format(cal.getTime()) + " > " + str + "\n"); } }
データベース
データベースを次の形式で提示しました。
CREATE TABLE IF NOT EXISTS node ( id INT (10) UNSIGNED NOT NULL, lat FLOAT (10,7) NOT NULL, lon FLOAT (10,7) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS way ( id INT (10) UNSIGNED NOT NULL ,PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS relation ( id INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS nd ( id INT (10) UNSIGNED NOT NULL ,id_way INT (10) UNSIGNED NOT NULL, id_node INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_way) REFERENCES way(id), FOREIGN KEY (id_node) REFERENCES node(id) ); CREATE TABLE IF NOT EXISTS tag_key ( id INT (10) UNSIGNED NOT NULL, k VARCHAR(25) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS tag_value ( id INT (10) UNSIGNED NOT NULL, v VARCHAR(255) NOT NULL, id_tag_key INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_tag_key) REFERENCES tag_key(id) ); CREATE TABLE IF NOT EXISTS node_tag ( id INT (10) UNSIGNED NOT NULL, id_node INT (10) UNSIGNED NOT NULL, id_tag INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_node) REFERENCES node(id), FOREIGN KEY (id_tag) REFERENCES tag_value(id) ); CREATE TABLE IF NOT EXISTS way_tag ( id INT (10) UNSIGNED NOT NULL, id_way INT (10) UNSIGNED NOT NULL, id_tag INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_way) REFERENCES way(id), FOREIGN KEY (id_tag) REFERENCES tag_value(id) ); CREATE TABLE IF NOT EXISTS relation_tag ( id INT (10) UNSIGNED NOT NULL, id_relation INT (10) UNSIGNED NOT NULL, id_tag INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_relation) REFERENCES relation(id), FOREIGN KEY (id_tag) REFERENCES tag_value(id) ); CREATE TABLE IF NOT EXISTS role ( id INT (10) UNSIGNED NOT NULL, v VARCHAR(25) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS member_node ( id INT (10) UNSIGNED NOT NULL, id_node INT (10) UNSIGNED NOT NULL, id_relation INT (10) UNSIGNED NOT NULL, id_role INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_relation) REFERENCES relation(id), FOREIGN KEY (id_role) REFERENCES role(id) ); CREATE TABLE IF NOT EXISTS member_way ( id INT (10) UNSIGNED NOT NULL, id_way INT (10) UNSIGNED NOT NULL, id_relation INT (10) UNSIGNED NOT NULL, id_role INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id),FOREIGN KEY (id_relation) REFERENCES relation(id), FOREIGN KEY (id_role) REFERENCES role(id) ); CREATE TABLE IF NOT EXISTS member_relation ( id INT (10) UNSIGNED NOT NULL, id_rel INT (10) UNSIGNED NOT NULL, id_relation INT (10) UNSIGNED NOT NULL, id_role INT (10) UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (id_relation) REFERENCES relation(id), FOREIGN KEY (id_role) REFERENCES role(id) ); INSERT INTO `tag_key` (`id`,`k`) VALUES ('1', 'aerialway'),('2', 'aeroway'),('3', 'amenity'),('4', 'barrier'),('5', 'boundary'),('6', 'building'),('7', 'craft'),('8', 'emergency'),('9', 'geological'),('10', 'highway'),('11', 'historic'),('12', 'landuse'),('13', 'leisure'),('14', 'man_made'),('15', 'military'),('16', 'natural'),('17', 'office'),('18', 'place'),('19','cycleway'),('20','bridge'),('21', 'power'),('22', 'public_transport'),('23', 'railway'),('24', 'route'),('25', 'shop'),('26', 'sport'),('27', 'tourism'),('28', 'waterway'),('29','tunnel'),('30','type'),('31','admin_level'),('100', 'addr:housenumber'),('101', 'addr:housename'),('102', 'addr:street'),('103', 'addr:place'),('104', 'addr:postcode'),('105', 'addr:city'),('106', 'addr:country'),('107', 'addr:province'),('108', 'addr:state'),('109', 'addr:interpolation'),('110', 'attribution'),('111', 'description'),('112', 'email'),('113', 'fax'),('114', 'phone'),('115', 'name'),('116', 'official_name');
作成されたテーブルの説明:
node :
id unique key、
lat、lon-座標。
way :
idユニークキー。
relation :
idユニークキー。
nd :
idは一意のキー(
カウンタはプログラム内にあります )、
id_wayは
ウェイテーブルの
idへのリンク、
id_nodeは
ノードテーブルの
idへのリンクです。
tag_key :
id一意キー、
k-テキスト値(
キーの説明 )
tag_value :
idは一意のキー(
カウンタはプログラム内にあります )、
vはテキスト値(
key value )、
id_tag_keyは
tag_keyテーブルの
idへのリンクです。
node_tag :
idは一意のキー(
カウンターはプログラム内にあります )、
id_nodeは
ノードテーブルの
idへのリンク、
id_tagは
tag_valueテーブルの
idへのリンク
です 。
way _ tag :
idは一意のキー(
カウンタはプログラム内にあります )、
id_wayは
wayテーブルの
idへのリンク、
id_tagは
tag_valueテーブルの
idへのリンク
です 。
relation_tag :
idは一意のキー(
カウンターはプログラム内にあります )、
id_relationは
リレーションテーブルの
idへのリンク、
id_tagは
tag_valueテーブルの
idへのリンク
です 。
役割 :
id一意のキー(
カウンターはプログラムに入ります )、
v-テキスト値(
属性値 )。
member_node :
idは一意のキーです(
プログラムの
カウンターはすべてのメンバーに共通です )
。id_nodeは
ノードテーブルの
idへのリンクです
。id_relationは
リレーションテーブルの
idへのリンクです。
member_way :
idは一意のキーです(
プログラムの
カウンターはすべてのメンバーに共通です )
。id_wayは
ウェイテーブルの
idへのリンクです
。id_relationは
リレーションテーブルの
idへのリンクです。
member_ relation :
idは一意のキーです(
プログラムの
カウンターはすべてのメンバーに共通です )
。id_relは
リレーションテーブルの
idへのリンクです
。id_relationは
リレーションテーブルの
idへのリンクです。
コード
public final class SqlDriver { private long iTagKey; private long iTagUK; private long iTagValue; private long iTagUValue; private long iNd; private long iTagNode; private long iTagWay; private long iTagRelation; private long iMember; private long iRole; private Statement statement; private Connection connection; private Window window; private Element e; public SqlDriver(Window w) { this.window = w; this.iRole = 1; this.iNd = 1; this.iMember = 1; this.iTagNode = 1; this.iTagWay = 1; this.iTagRelation = 1; this.iTagUK = 1; this.iTagUValue = 1; this.iTagValue = 1; this.e = new Element("node", 0); }
ロジック
SAX XMLパーサー
ウィンドウでプログレスバーを使用したため、ファイルは2回読み取られました。最初の行では行数をカウントし、2番目の行ではデータベースに書き込みます。XMLコンストラクター
public class XML extends Thread { private Window window; private SqlDriver sql; public XML(SqlDriver sql, Window window ) { this.window = window; this.sql = sql; } @Override public void run() { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(false); SAXParser parser; InputStream xmlData = null; try { xmlData = new FileInputStream(window.getFilePathValue().getText()); parser = factory.newSAXParser(); XMLReader reader = new XMLReader(); window.addLog(" "); parser.parse(xmlData, reader); window.addLog(" : " + Long.toString(reader.getLine())); window.addLog("node: " + Long.toString(reader.getNode())); window.addLog("way: " + Long.toString(reader.getWay())); window.addLog("relation: " + Long.toString(reader.getRelation())); window.addLog(" MySQL"); xmlData.close(); xmlData = new FileInputStream(window.getFilePathValue().getText()); XMLParser xml =new XMLParser(sql, window, reader.getLine()); parser.parse(xmlData, xml); } catch (FileNotFoundException e) { e.printStackTrace();
XMLリーダー
public class XMLReader extends DefaultHandler { private long line; private long node; private long way; private long relation; public XMLReader() { this.line = 0; this.node = 0; this.way = 0; this.relation = 0; } @Override public void startElement(String uri, String name, String eName, Attributes atts) { this.line++; if (eName.equals("way")) this.way++; if (eName.equals("node")) this.node++; if (eName.equals("relation")) this.relation++; } @Override public void endElement(String uri, String name, String eName) { } @Override public void startDocument() throws SAXException { super.startDocument(); } @Override public void endDocument() throws SAXException { super.endDocument(); } }
XMLパーサー
public class XMLParser extends DefaultHandler { private int ipmplement; private long line; private LogicOSM logic; private Window widnow; private long onePercent; private long nextPercent; private boolean extension; private String elemName; private Long idStart; public XMLParser(SqlDriver sql, Window window, long maxLine) { this.line = 1; this.widnow = window; this.logic = new LogicOSM(sql); this.onePercent = (long) (maxLine / 1000); this.nextPercent = onePercent; if (sql.getE().getId() != 0) { this.extension = true; this.elemName = sql.getE().getName(); this.idStart = sql.getE().getId(); this.ipmplement = 0; } else this.extension = false; } @Override public void startElement(String uri, String name, String eName, Attributes atts) { if (ipmplement == 0) {
まあ、実際にはコントローラー
public class Controler{ private final Window window; private final SqlDriver sql; public Controler() { this.window = new Window(); window.start(); this.sql = new SqlDriver(window); } public void init() { System.out.println(" run Controller"); try { window.getFrame().setVisible(true); window.addLog("Hello"); window.getConnected().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(sql.getConnection()) sql.loadSchema(); window.getConnected().setEnabled(false); window.getExport().setEnabled(true); } }); window.getExport().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { window.addLog("Export"); window.getExport().setEnabled(false); XML xml = new XML(sql, window); xml.start(); } }); } catch (Exception e) { e.printStackTrace(); } }
そして結果
