属性映射经常用于属性表或Excel表的赋值,比如按用地用海表对规划用地的用地编码或用地名称赋值,将汇总好的用地指标表赋值给已经制好的Excel模板等。
下面试着在ArcGIS Pro SDK中实现功能上述这两个功能。
一、Excel表格映射到属性表Table
1、要实现的效果
如上图所示,打开【Excel表格映射到Table】工具框,选择输入的要素图层,如【规划用地】,接着输入参照字段和映射字段,最后打开用来映射的Excel表,注意这里打开的Excel表是到【sheet】级的。
点击执行,效果如下:
生成结果中,映射字段会按照映射表的对应键值一一赋值,如果参照字段不在映射表中,则不赋值。
2、实现流程
这里主要是采用几个GP工具【连接字段、计算字段】来实现的,核心步骤和代码如下:
首先需要获取Excel表中的2个表头,即字段名:
// 参数获取
string map_tabel = textExcelPath.Text;
string in_data = combox_fc.Text;
string in_field = combox_bmField.Text;
string map_field = combox_bmField_Copy.Text;
// 获取连接表的2个字段名
string exl_field01 = GetCellFromExcel(map_tabel, "A1");
string exl_field02 = GetCellFromExcel(map_tabel, "B1");
List<string> fields = new List<string>() { exl_field02 };
// 从Excel文件中获取Cellvalue
public static string GetCellFromExcel(string excelPath, string range)
{
// 建立 Excel 应用程序对象
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
// 获取Excel文件名和表名
List<string> files = DecomposeExcel(excelPath);
string excel_name = files[0];
string sheet_name = files[1];
// 打开 Excel 文件
Workbook workbook = excelApp.Workbooks.Open(excel_name);
// 获取工作表
Worksheet worksheet = workbook.Worksheets[sheet_name];
// 获取单元格
string Cellvalue = worksheet.Range[range].Value.ToString();
// 保存并关闭 Excel 文件和应用程序对象
workbook.Close(true);
excelApp.Quit();
// 返回value
return Cellvalue;
}
这里还调用了一个方法【DecomposeExcel】,用于把输入的Excel文件分解为文件名和表名,代码如下:
// 分解Excel的文件名和表名
public static List<string> DecomposeExcel(string excelPath)
{
// 设置空列表
List<string> list = new List<string>();
// 获取最后一个"\"的位置
int index = excelPath.LastIndexOf("\\");
// 获取exl文件名
string excel_name = excelPath.Substring(0, index);
// 获取表名
string sheet_name = excelPath.Substring(index + 1, excelPath.Length - index - 2);
// 将exl文件名和表名加入列表
list.Add(excel_name);
list.Add(sheet_name);
// 返回列表
return list;
}
然后调用GP工具【连接字段】,以参照字段为连接字段,将Excel表连接至属性表中:
// 连接字段
JoinField(in_data, in_field, map_tabel, exl_field01, fields);
// 连接字段
public static async void JoinField(string in_data, string in_field, string join_table, string join_field, List<string> fields, bool isOutput = false)
{
// 设置默认GPExecuteToolFlags
GPExecuteToolFlags executeFlags = GPExecuteToolFlags.AddToHistory;
if (isOutput)
{
executeFlags = GPExecuteToolFlags.AddToHistory | GPExecuteToolFlags.AddOutputsToMap;
}
// 执行GP工具
var par_JoinField = Geoprocessing.MakeValueArray(in_data, in_field, join_table, join_field, fields, "NOT_USE_FM", "");
await QueuedTask.Run(() => Geoprocessing.ExecuteToolAsync("management.JoinField", par_JoinField, null, null, null, executeFlags));
}
调用GP工具【计算字段】,将连接到属性表里的目标字段赋值给属性表里的映射字段:
// 计算字段
CalculateField(in_data, map_field, "!" + exl_field02 + "!");
// 计算字段
public static async void CalculateField(string in_data, string field, string expression, bool isOutput = false)
{
// 设置默认GPExecuteToolFlags
GPExecuteToolFlags executeFlags = GPExecuteToolFlags.AddToHistory;
if (isOutput)
{
executeFlags = GPExecuteToolFlags.AddToHistory | GPExecuteToolFlags.AddOutputsToMap;
}
// 执行GP工具
var par_CalculateField = Geoprocessing.MakeValueArray(in_data, field, expression, "PYTHON3", "", "", "NO_ENFORCE_DOMAINS");
await QueuedTask.Run(() => Geoprocessing.ExecuteToolAsync("management.CalculateField", par_CalculateField, null, null, null, executeFlags));
}
赋完值,顺便还可以删掉连接进来的字段。
以上便实现了将Excel表格映射到Table的功能。
二、属性表Table映射到Excel表格
1、要实现的效果
如上图所示,打开【Table映射到Excel表格】工具框,选择要赋值的Excel表,输入参照列和映射列(例子中是第1列和第2例),然后输入表格Table(例子里是一个汇总统计表),再输入参照字段和映射字段。
点击执行,效果如下:
生成结果中,Excel表格会根据汇总表的值进行填写,如果汇总表中没有相应的参照字段,则不会填写。
这个工具用处是很多的,例如生成【用地用海表,村庄结构功能表……】等一系列表格。
2、实现流程
第一步要从属性表Table中将对应的键值提取出来,输出一个字典,方便后面使用:
// 参数获取
string map_tabel = combox_table.Text;
string in_field = combox_bmField_in.Text;
string map_field = combox_bmField_map.Text;
string excelPath = textExcelPath.Text;
int sheet_in_col = int.Parse(txtbox01.Text);
int sheet_map_col = int.Parse(txtbox02.Text);
// 将映射属性表中获取字典Dictionary
Dictionary<string, string> dict = await QueuedTask.Run(() => GetDictFromTable(map_tabel, in_field, map_field));
// 从Table中获取Dictionary
public static async Task<Dictionary<string, string>> GetDictFromTable(string in_table, string in_field_01, string in_field_02)
{
Dictionary<string, string> dict = new();
// 根据图层名找到当前图层
var map = MapView.Active.Map;
StandaloneTable initlayer = map.FindStandaloneTables(in_table)[0];
await QueuedTask.Run(() =>
{
using (ArcGIS.Core.Data.Table table = initlayer.GetTable())
{
using (RowCursor rowCursor = table.Search(null, false))
{
TableDefinition tableDefinition = table.GetDefinition();
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
// 获取value
var key = row[in_field_01].ToString();
var value = row[in_field_02].ToString();
// 如果没有重复key值,则纳入dict
if (!dict.Keys.Contains(key))
{
dict.Add(key, value);
}
}
}
}
}
});
return dict;
}
获取用来映射的字典后,就可以打开Excel文件进行赋值了。同样的,这里还是要先把Excel文件名进行一个分解:
// 建立 Excel 应用程序对象
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
// 获取Excel文件名和表名
List<string> files = DecomposeExcel(excelPath);
string excel_name = files[0];
string sheet_name = files[1];
// 打开 Excel 文件
Workbook workbook = excelApp.Workbooks.Open(excel_name);
// 获取工作表
Worksheet worksheet = workbook.Worksheets[sheet_name];
// 获取Excel表格中的数据,将特定列作为值
for (int row = 1; row <= worksheet.UsedRange.Rows.Count; row++)
{
// 获取对照值
string in_value = worksheet.Cells[row, sheet_in_col].Value.ToString();
// 赋值
if (dict.Keys.Contains(in_value))
{
worksheet.Cells[row, sheet_map_col].Value = dict[in_value];
}
}
// 保存并关闭 Excel 文件和应用程序对象
workbook.Close(true);
excelApp.Quit();
以上便实现了将Table映射到Excel表格的功能。
完整代码可以查看文章末尾放出的工程文件。
三、工程文件分享
最后,放上工程文件的链接:
AttributeMapperhttps://pan.baidu.com/s/1J79C5Qr7ClEyq5mrf12I9g?pwd=dqpjPS:可以直接点击...bin\Debug\net6.0-windows\下的.esriAddinX文件直接安装。