Skip to content

Commit

Permalink
ユーザーが記述したマッピングルールによる属性名の書き換え(CLI) (#324)
Browse files Browse the repository at this point in the history
#251 の一部

ユーザーがマッピングルールのJSONファイルを記述し、指定することで、任意の属性名を書き換えることができる。

このPRでは、CLIによるルール指定・書き換えまでを対応している。

## 変更

- [x] 「マッピングルール」記述の定義
  - `{ "rename": { "before1": "after1" } }` という形式にしている
  - `rename` と名前空間を区切ることで、将来的に他の「ルール」も設定可能である
- [x] Transformerでのルールの取り扱い
  - Requirementsを追加した
- [x] 名前書換トランスフォーマーで、任意の書換ルールを適用
  - `extend_rename_map(map)` メソッドを追加した
- [x] CLI
  - `--rules` オプションの追加
  - 指定されたJSONファイルを読み、Transformerのrequirementをセットする

## 備考

- `id`, `type` は書き換えできない(元データでの直接の「属性名」ではないため)
  - これらを書き換える必要はない/書き換えさせるべきではないと考える
- Shapefile sinkの場合
  - 既存の書き換えルールがnusamaiに組み込まれている
  - ユーザーの書き換えルールは、その既存ルールを上書きする(同名の元属性がある場合、ユーザーが定義したものが利用される)
  
## 質問

- `KeyValuePairAttribute` は書き換えできない
  - Q: なぜできないのか、それで良いのかがわかっていない
  
## 次にやること

#251

- GUIでのルールファイル指定 #331 
- ワイルドカード指定


## 例

JSONファイルのルール記述

```json
{
    "rename": {
        "buildingIDAttribute": "建物ID",
        "address": "住所",
        "buildingDataQualityAttribute": "データ品質",
        "buildingDetailAttribute": "建物詳細",
        "genericAttribute": "ジェネリック",
        "measuredHeight": "高さ",
        "buildingDisasterRiskAttribute": "災害リスク",
        "name": "名前"
    }
}
```

```sh
$ cargo run -- plateau/13100_tokyo23-ku_2022_citygml_1_2_op/udx/bldg/53392546_bldg_6697_2_op.gml --sink geojson --output ~/Desktop/tmp.geojson --rules ./rules.json
```

<img width="775" alt="image"
src="https://github.com/MIERUNE/PLATEAU-GIS-Converter/assets/595008/ce3453f4-6b5a-4834-89fb-cc93e0696c1c">



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit


- **新機能**
    - コマンドライン引数に `rules` オプションを追加しました。
    - ユーザーが指定したルールを使用して属性名をリネームする機能を追加しました。

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
sorami authored Feb 26, 2024
1 parent d7fb003 commit 5bcd9a4
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 4 deletions.
23 changes: 22 additions & 1 deletion nusamai/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use nusamai::pipeline::Canceller;
use nusamai::sink::{DataSink, DataSinkProvider};
use nusamai::source::citygml::CityGmlSourceProvider;
use nusamai::source::{DataSource, DataSourceProvider};
use nusamai::transformer::MappingRules;
use nusamai::transformer::{MultiThreadTransformer, Requirements};
use nusamai::transformer::{NusamaiTransformBuilder, TransformBuilder};
use nusamai::BUILTIN_SINKS;
Expand All @@ -30,6 +31,10 @@ struct Args {
#[arg(long)]
output: String,

/// Specify the mapping rules JSON file
#[arg(long)]
rules: Option<String>,

/// Output schema
#[arg(long)]
schema: Option<String>,
Expand Down Expand Up @@ -125,7 +130,21 @@ fn main() {
sink_provider.create(&sink_params)
};

let requirements = sink.make_transform_requirements();
let requirements = if let Some(rules_path) = &args.rules {
let mapping_rules = {
let file_contents =
std::fs::read_to_string(rules_path).expect("Error reading rules file");
let mapping_rules: MappingRules =
serde_json::from_str(&file_contents).expect("Error parsing rules file");
mapping_rules
};
Requirements {
mapping_rules: Some(mapping_rules),
..sink.make_transform_requirements()
}
} else {
sink.make_transform_requirements()
};

let source = {
// glob input file patterns
Expand Down Expand Up @@ -221,6 +240,8 @@ mod tests {
.arg("noop")
.arg("--output")
.arg("dummy")
.arg("--rules")
.arg("./tests/rules.json")
.arg("--schema")
.arg("schema.json")
.assert();
Expand Down
10 changes: 10 additions & 0 deletions nusamai/src/transformer/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::transformer;
pub struct Requirements {
/// Whether to shorten field names to 10 characters or less for Shapefiles.
pub shorten_names_for_shapefile: bool,
/// Mapping rules defined by the user
pub mapping_rules: Option<transformer::MappingRules>,
pub tree_flattening: TreeFlatteningSpec,
pub resolve_appearance: bool,
pub mergedown: MergedownSpec,
Expand All @@ -19,6 +21,7 @@ impl Default for Requirements {
fn default() -> Self {
Self {
shorten_names_for_shapefile: false,
mapping_rules: None,
tree_flattening: TreeFlatteningSpec::None,
resolve_appearance: false,
mergedown: MergedownSpec::RemoveDescendantFeatures,
Expand All @@ -29,6 +32,7 @@ impl Default for Requirements {

pub struct Request {
pub shorten_names_for_shapefile: bool,
pub mapping_rules: Option<transformer::MappingRules>,
pub tree_flattening: TreeFlatteningSpec,
pub apply_appearance: bool,
pub mergedown: MergedownSpec,
Expand All @@ -39,6 +43,7 @@ impl From<Requirements> for Request {
fn from(req: Requirements) -> Self {
Self {
shorten_names_for_shapefile: req.shorten_names_for_shapefile,
mapping_rules: req.mapping_rules,
tree_flattening: req.tree_flattening,
apply_appearance: req.resolve_appearance,
mergedown: req.mergedown,
Expand Down Expand Up @@ -107,6 +112,11 @@ impl TransformBuilder for NusamaiTransformBuilder {
if self.request.shorten_names_for_shapefile {
renamer.load_default_map_for_shape();
}
// Rename rules by the user are set after `load_default_map_for_shape()`,
// therefore it will override the default shapefile renames if there are conflicts
if let Some(mapping_rules) = &self.request.mapping_rules {
renamer.extend_rename_map(mapping_rules.rename.clone());
}
renamer
});

Expand Down
6 changes: 3 additions & 3 deletions nusamai/src/transformer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! The transformer stage that preprocesses the attributes and geometry of the entities.

mod builder;
mod rules;
mod runner;
pub mod transform;

pub use builder::*;
pub use rules::*;
pub use runner::*;
pub use transform::{
DataFlatteningOption, FeatureFlatteningOption, ObjectFlatteningOption,
};
pub use transform::{DataFlatteningOption, FeatureFlatteningOption, ObjectFlatteningOption};

use crate::pipeline::{Feedback, Parcel, Receiver, Result, Sender};

Expand Down
12 changes: 12 additions & 0 deletions nusamai/src/transformer/rules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};

/// Rules specified by the user in a JSON file
#[derive(Serialize, Deserialize, Debug)]
pub struct MappingRules {
pub rename: RenameRules,
}

/// Rules specified by the user to rename the attributes
/// Used by the `EditFieldNamesTransform` transformer
pub type RenameRules = HashMap<String, String>;
5 changes: 5 additions & 0 deletions nusamai/src/transformer/transform/attrname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ impl EditFieldNamesTransform {
}
}
}

pub fn extend_rename_map(&mut self, map: HashMap<String, String>) {
// Note: the value is updated if the key already exists
self.rename_map.extend(map);
}
}

impl Transform for EditFieldNamesTransform {
Expand Down
12 changes: 12 additions & 0 deletions nusamai/tests/rules.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"rename": {
"buildingIDAttribute": "建物ID",
"address": "住所",
"buildingDataQualityAttribute": "データ品質",
"buildingDetailAttribute": "建物詳細",
"genericAttribute": "ジェネリック",
"measuredHeight": "高さ",
"buildingDisasterRiskAttribute": "災害リスク",
"name": "名前"
}
}

0 comments on commit 5bcd9a4

Please sign in to comment.