応用スキーマは、特定の種類のデータセットをXML形式で記述する場合に従わなければならない仕様であり、あるXML文書についての応用スキーマが開示されなかったり、開示されたとしてもXML文書がその応用スキーマに適合していなかったりした場合には、一般にそのXML文書を正しく読むことはできません。
XML形式で提供するデータは、XMLの規格や応用スキーマに厳密に適合していなければなりませんが、その点でルーズであることにより、利用が難しいデータを見かけることもあります。
国土数値情報「行政区域」データにおけるXML要素名等は、応用スキーマ文書「国土数値情報(行政区域)製品仕様書 第 2.3 版」で定義されていますが、平成25年のデータにおける行政区域クラス、およびその属性を記述しているXML要素名はそれに適合していません(2017年4月2日にダウンロードした 平成25年 東京都 のデータで確認)。
クラス | 属性 | XML要素名 (製品仕様書2.3版) | XML要素名 (平成25年データ) |
---|---|---|---|
行政区域 | AdministrativeBoundary | AdministrativeArea | |
範囲 | bounds | are | |
都道府県名 | prefectureName | prn | |
支庁・振興局名 | subPrefectureName | sun | |
郡・政令都市名 | countyName | con | |
市区町村名 | cityName | cn2 | |
行政区域コード | administrativeAreaCode | aac |
平成25年のデータ作成時の応用スキーマでは現在と異なる要素名が定義されていたのか、平成25年のデータが規格外なのか、あるいはその他の事情があるのか、理由は定かではありませんが、いずれにせよ、現在の製品仕様書に準拠して作成されたアプリケーションでこのデータを利用しようとするならば、XML要素名を変更する必要があります。
FMEでは、XML文書を処理するために多くのトランスフォーマーが用意されています。ここではそのひとつ、XMLUpdater トランスフォーマーを使い、国土数値情報「行政区域」の平成25年のデータ (XML文書) を、現在の製品仕様書に適合するように更新するワークスペース例を掲げます。
FME 2017.0.0.1 build 17271
FMEワークスペース例
[DATAFILE] リーダー: 国土数値情報「行政区域」データ (更新前XML文書) を読み込む
StringReplacer: 更新前XMLの誤記修正 (詳細は後述)
XMLUpdater: 行政区域の属性を記述しているXML要素名の変更
XMLFormatter: 更新後XMLの書式やエンコーディングの設定
[DATAFILE] ライター: 更新後XMLをファイルに出力
行政区域クラスXML要素の例
<!-- 更新前 --> <ksj:AdministrativeArea gml:id="gy2"> <ksj:are xlink:href="#sf2"/> <ksj:prn>東京都</ksj:prn> <ksj:sun></ksj:sun> <ksj:con>足立区</ksj:con> <ksj:cn2></ksj:cn2> <ksj:aac codeSpace="AdministrativeAreaCode.xml">13121</ksj:aac> </ksj:AdministrativeArea> |
<!-- 更新後 --> <ksj:AdministrativeBoundary gml:id="gy2"> <ksj:bounds xlink:href="#sf2"/> <ksj:prefectureName>東京都</ksj:prefectureName> <ksj:subPrefectureName/> <ksj:countyName>足立区</ksj:countyName> <ksj:cityName/> <ksj:administrativeAreaCode codeSpace="AdministrativeAreaCode.xml">13121</ksj:administrativeAreaCode> </ ksj:AdministrativeBoundary> |
[DATAFILE] リーダー/ライターによって、XMLを含む任意のフォーマットのファイルの読み書きができます。リーダーの Read Whole File at Once (ファイル全体を一度に読む) パラメーターを Yes に設定してファイルを読み込むと、そのファイルの内容 - この場合はXML文書の全体を格納した data_file_data 属性を持つフィーチャーが出力されます (1ファイルにつき1フィーチャー)。
このワークスペース例を作成している過程で、国土数値情報「行政区域」の平成25年のデータのルート要素に誤記があるのを見つけました。
<?xml version="1.0" encoding="UTF-8"?>
<ksj:Dataset
gml:id= "N03Dataset"
xmlns:ksj="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:schemaLocation="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app KsjAppSchema-N03-v2_0.xsd">
<ksj:Dataset
gml:id= "N03Dataset"
xmlns:ksj="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:schemaLocation="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app KsjAppSchema-N03-v2_0.xsd">
XMLの仕様に忠実なソフトウェアは、この誤記があることによってXML文書全体の読み込みを拒否することがあります。FMEがXML文書の更新等を行うために使用している XQuery プロセッサー (Zorba XQuery Processor) もこの誤記を許容しないので、まず、StringReplacer によって "xmlns:schemaLocation" を "xsi:schemaLocation" に置き換えました。
この修正を施したうえで XMLUpdater によって、行政区域の属性を記述するためのXML要素名を、現在の応用スキーマに準拠した名前に変更しました。
XMLUpdater には2つの入力ポート - Document と Update があり、更新したいXML文書を属性として持っているフィーチャーは Document ポートの方に入力します。
Update ポートから入力したフィーチャーの属性をXML更新用のパラメーター (Value) として使うこともできますが、この例では、その必要はありません。ただし、XMLUpdater を起動するには、少なくともひとつのフィーチャーを Update ポートに入力する必要があります。そのため、Creator を Update ポートを接続して、何も属性を持たないフィーチャーを1個だけ入力しています。
XMLUpdater パラメーター設定画面
XMLUpdater で要素名を変更する場合は、パラメーター設定画面の Updates テーブルで、変更するノード (XML要素) ごとに次の事項を設定します。
- Update Type: Rename (ノード名を変更) を選択
- XML Path: 変更対象ノードのXML文書内での位置を示す XPath
- Value Type: Plain Text (変更後のノード名を文字列で指定する場合)
- Value: 変更後の文字列
declare namespace ksj="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app";
for $x in //ksj:AdministrativeArea return rename node $x as 'ksj:AdministrativeBoundary',
for $x in //ksj:are return rename node $x as 'ksj:bounds',
for $x in //ksj:prn return rename node $x as 'ksj:prefectureName',
for $x in //ksj:sun return rename node $x as 'ksj:subPrefectureName',
for $x in //ksj:con return rename node $x as 'ksj:countyName',
for $x in //ksj:cn2 return rename node $x as 'ksj:cityName',
for $x in //ksj:aac return rename node $x as 'ksj:administrativeAreaCode'
for $x in //ksj:AdministrativeArea return rename node $x as 'ksj:AdministrativeBoundary',
for $x in //ksj:are return rename node $x as 'ksj:bounds',
for $x in //ksj:prn return rename node $x as 'ksj:prefectureName',
for $x in //ksj:sun return rename node $x as 'ksj:subPrefectureName',
for $x in //ksj:con return rename node $x as 'ksj:countyName',
for $x in //ksj:cn2 return rename node $x as 'ksj:cityName',
for $x in //ksj:aac return rename node $x as 'ksj:administrativeAreaCode'
注1: この例では、[DATAFILE] リーダーでXML文書を読み込み、それを属性として持っているフィーチャーを XMLUpdater の Document ポートから入力しましたが、XMLUpdater の XML Input パラメーターで "XML File" を選択することにより、XML File パラメーターでファイル名を指定してXML文書を直接読み込ませる方法もあります。その方が効率が良さそうですが、国土数値情報「行政区域」平成25年のデータには前述の誤記があり、それを修正しないと XMLUpdater はXML文書を解析できなかったため、採用できませんでした。
注2: XMLUpdater トランスフォーマーではノード名の変更のほかに、ノードの置換、ノードの内容の置換、ノードの削除、ノードの内容の削除、ノードの挿入を行うことができます。
注3: XMLXQueryUpdater トランスフォーマーでは XQuery 式を直接指定し、それに基づくXML更新を行うことができます。XMLUpdater では対応できない複雑で高度なXML更新も、XMLXQueryUpdater を使えば可能になる場合があります (本記事末尾の [補足] 参照)。
次の XMLFormatter では、必要に応じて、インデント数、余分な空白の取り扱い、値を持たない要素の記述方法、エンコーディングなど、XML文書の書式全般を設定できます。この例では更新後XMLのエンコーディングを UTF-8 に設定しましたが、更新前XMLのエンコーディングも UTF-8 なので、必須ではありません。
ただし、[DATAFILE] ライターフィーチャータイプでは Character Encoding パラメーターを明示的に UTF-8 に設定する必要があります。
[DATAFILE] ライターフィーチャータイプ
補足: XMLXQueryUpdater (やや高度な XQuery 式) の例
結果をチェックしていて、国土数値情報「行政区域」では、東京23区名が countyName (郡・政令都市名) 要素に記述されていることに気がつきました。平成25年に限らずどの年のデータでもそのようなので、仕様上は間違いないのだとは思いますが、一般的には、どちらかと言えば「市区町村名」の範疇で取り扱う方が多いような気がします。
仮に、countyName 要素に区名 "○○区" が記述されている場合、それを cityName 要素に記述し、countyName 要素からは削除することが必要になったとすれば、XMLXQueryUpdater によって次のような XQuery 式を実行すれば良さそうです。
declare namespace ksj="http://nlftp.mlit.go.jp/ksj/schemas/ksj-app";
for $x in //ksj:countyName[fn:ends-with(text(), '区')]
return (replace value of node $x/../ksj:cityName with $x/text(),
replace value of node $x with '')
for $x in //ksj:countyName[fn:ends-with(text(), '区')]
return (replace value of node $x/../ksj:cityName with $x/text(),
replace value of node $x with '')
- 末尾が「区」である文字列 (区名) を内容とする全ての ksj:countyName 要素について、
- その sibling (兄弟姉妹) 関係にある ksj:cityName 要素の内容をその区名で置き換え、
- ksj:countyName 要素の内容は空文字列 '' で置き換える (つまり、内容を削除する)。
0 件のコメント:
コメントを投稿