不求甚解

此博客为个人学习之用,如与其他作品雷同,纯属巧合。

导航

R2R 映射 XML 语法速查表

  R2R(Row-to-Row)映射 XML 是数据同步场景中常用的配置文件,核心作用是定义 “源表字段→目标表字段” 的转换规则,无需修改代码即可灵活调整数据流向。

一、节点层级关系(自上而下)

节点父节点作用说明
<table-mappings> —(根节点) 全局容器:包含一个或多个表映射配置
<table-mapping> <table-mappings> 源表绑定:指定一个源表及其字段映射规则
<mappings> <table-mapping> 规则分组容器:组织多个目标表映射(支持一对多)
<mapping> <mappings> 目标表绑定:关联一个目标表,并可指定同步策略(如全量/增量)
<column> <mapping> 字段级转换:定义单个字段如何从源到目标(直传或表达式计算)

二、关键属性说明(必用项)

节点属性说明示例
<table-mappings> xmlns:xsi 声明 XML Schema 实例命名空间 http://www.w3.org/2001/XMLSchema-instance
  xsi:noNamespaceSchemaLocation 指向 XSD 校验文件路径(用于语法验证) ../r2RMapping.xsd
<table-mapping> src 源表名(必填) src="pt_outhosp_order"
<mapping> targ 目标表名(必填) targ="ods_outhosp_order"
  strategy 同步策略(可选,如 full / incremental 或 type="incremental"或 type="full"
<column> src 源字段名;若为 "N/A" 表示通过表达式生成 src="order_id" 或 src="N/A"
  targ 目标字段名(必填) targ="orderid"
  value 字段值表达式(仅当 src="N/A" 时使用) value='body["create_time"] == null ? null : body["create_time"]'
 

三、高频表达式模板(直接复用)

Java 风格表达式引擎(支持 body['字段']、三元运算 ? :.equals(),不支持 SQL 函数)所整理的 R2R(Record-to-Record)映射高频实用模板教程。

所有模板均基于 <column src="..." targ="..." value="..."/> 语法,可直接复制使用,并附带说明和注意事项。

1. 空值或 "-" 转 null

<column src="N/A" targ="目标字段" value='body["源字段"] == null || "-".equals(body["源字段"]) || "".equals(body["源字段"]) ? null : body["源字段"]'/>

2. 代码转名称(值映射)

<column src="N/A" targ="gender" value='"1".equals(body["sex"]) ? "男" : "2".equals(body["sex"]) ? "女" : "未知"'/>

3. 时间标准化(10位补时分秒,19位原样,其他 null)

<column src="N/A" targ="event_time" value='body["date_str"] == null || "-".equals(body["date_str"]) ? null : body["date_str"].length() == 10 ? body["date_str"] + " 00:00:00" : body["date_str"].length() == 19 ? body["date_str"] : null'/>

4. Y/N 转布尔字符串

<column src="N/A" targ="is_valid" value='"Y".equals(body["flag"]) ? "true" : "false"'/>

5. 截取前6位(如身份证地区码)

<column src="N/A" targ="region_code" value='body["id_card"] != null && body["id_card"].length() >= 6 ? body["id_card"].substring(0,6) : null'/>

6. 空值设默认值

<column src="N/A" targ="category" value='body["type"] == null || "".equals(body["type"]) ? "通用" : body["type"]'/>

7. 拼接两字段(安全处理 null)

<column src="N/A" targ="full_name" value='(body["last"] == null ? "" : body["last"]) + (body["first"] == null ? "" : " " + body["first"])'/>

四、基础原则及示例

  • 所有字段通过 body['字段名'] 引用
  • 使用单引号包裹整个 value 表达式(避免 &quot;
  • 优先用 "常量".equals(body['字段']) 防止空指针
  • 复杂逻辑用嵌套三元运算模拟 if-else
<table-mapping src="pt_outhosp_order">
    <mappings>
        <mapping targ="yh_mz_yzmxjl" type="all">
                <!-- 1. 系统更新时间:将目标表 xtsjgxsj 字段设置为当前系统日期时间 -->
                <column src="N/A" targ="xtsjgxsj" value="'$(sysdate)'"/>
                <!-- 2. 操作类型标识:将 dsql_optype 字段设置为 'update',标识操作类型为更新 -->
                <column src="N/A" targ="dsql_optype" value="'update'"/>
                <!-- 3. 主键字段映射:将源表 system_source 字段作为主键,映射到目标表 hisbb 字段 -->
                <column src="system_source" targ="hisbb" pk="true"/>
                <!-- 4. 操作类型标识:将 dsql_optype 字段设置为 'delete',标识操作类型为删除 -->
                <column src="N/A" targ="dsql_optype" value="'delete'"/>
                <!-- 5. 操作类型标识:将 dsql_optype 字段设置为 'batch_delete',标识操作类型为批量删除 -->
                <column src="N/A" targ="dsql_optype" value="'batch_delete'"/>
                <!-- 6. 报告流水号构造:通过拼接 request_no 和 report_serial_no 构造目标表 bglsh 字段的值 -->
                <column src="N/A" targ="bglsh" value="body['request_no']+'_'+body['report_serial_no']"/>
                <!-- 7. 年龄字段处理:根据 age_unit 的值判断,若为 '1''',则取 age 的值,否则为 null,存入 nls 字段 -->
                <column src="N/A" targ="nls" value="'1'.equals(body['age_unit'])? body['age']:'岁'.equals(body['age_unit'])? body['age']:null"/>
                <!-- 8. 就诊性质字段:将目标表 jzxzmc 字段固定设置为 '住院' -->
                <column src="N/A" targ="jzxzmc" value="'住院'"/>
                <!-- 9. diag_date源字段三种情况(1null2"-"3、其他19位时间格式),目标字段时间类型,非必填-->
                <column src="N/A" targ="zdrqsj" value="body['diag_date'] == null || '-'.equals(body['diag_date']) ? null : body['diag_date']"/>
                <!-- 10. 如果age源字段可能不存在,目标字段nl字符串类型且必填,值为默认值或者age-->
                <column src="N/A" targ="nl" value="body['age'] == null ? '18' : body['age']"/>
                <!-- 11. 如果diag_date源字段可能不存在,目标字段testdt是时间类型且必填,默认值系统时间或者diag_date-->
                <column src="N/A" targ="testdt" value="body['diag_date'] == null ? '$(sysdate)' : body['diag_date']"/>
                <!-- 12. 如果diag_date源字段可能不存在,目标字段testdt是时间类型且必填,默认值自定义时间或者diag_date-->
                <column src="N/A" targ="testdt" value="body['diag_date'] == null ? T(java.time.LocalDate).of(2000,1,1) : T(java.time.LocalDate).parse(body['diag_date'])"/>
            </mapping>
        </mappings>
    </table-mapping>
</table-mappings>

 

 

五、推测可用的函数表达式

类型方法 / 操作示例适用场景推荐表达式写法
空值判断 == null body["name"] == null 判断字段是否缺失 body["字段"] == null
字符串相等 .equals(String) "Y".equals(body["flag"]) 安全比较字符串值 始终将常量放左边,避免 NPE
空字符串判断 "".equals(...) "".equals(body["code"]) 过滤空字符串 与 == null 联用:body["x"] == null || "".equals(body["x"])
字符串长度 .length() body["id"].length() == 18 校验固定长度(如身份证、手机号) body["字段"].length() == N
截取子串 .substring(start, end) body["date"].substring(0, 4) 提取年份、地区码、编码段等 确保长度足够:len >= end ? str.substring(...) : null
去除空格 .trim() body["name"].trim() 清洗前后空格 常与判空联用:"".equals(body["x"].trim())
大小写转换 .toLowerCase() / .toUpperCase() body["code"].toLowerCase() 统一大小写(如匹配、去重) 一般用于比较前标准化
前缀判断 .startsWith(String) body["code"].startsWith("A") 分类、路由、过滤 body["字段"].startsWith("前缀")
后缀判断 .endsWith(String) body["file"].endsWith(".txt") 文件类型、状态标识判断 同上
查找子串位置 .indexOf(String) body["email"].indexOf("@") >= 0 判断是否包含某字符/子串 str.indexOf("x") != -1 等价于“包含”
字符串拼接 + body["a"] + "-" + body["b"] 组合字段(姓名、地址、编码) 对可能为 null 的字段先转空串:(x == null ? "" : x) + ...
逻辑与 && cond1 && cond2 多条件同时成立 XML 中建议写为 &amp;&amp;
逻辑或 || cond1 || cond2 多条件任一成立 XML 中建议写为 &amp;|
逻辑非 ! ! "Y".equals(x) 取反条件 常用于排除特定值
三元条件 ? : x == null ? "默认" : x 条件赋值、默认值、映射转换 支持嵌套,但建议不超过 3 层