MarkLogic Entity Services提取数组异常问题求助
问题:MarkLogic Entity Services生成重复数组而非单数组多元素
预期输出
<policies> <policy> <policyType>Mercedes-Benz</policyType> <policyNumber>40-294-9278</policyNumber> <policyZip>18706</policyZip> </policy> <policy> <policyType>Mitsubishi</policyType> <policyNumber>17-516-9783</policyNumber> <policyZip>18706</policyZip> </policy> <policy> <policyType>Subaru</policyType> <policyNumber>71-370-4976</policyNumber> <policyZip>18706</policyZip> </policy> </policies>
实际输出
<policies datatype="array"> <policy> <policyType>Mercedes-Benz</policyType> <policyNumber>40-294-9278</policyNumber> </policy> </policies> <policies datatype="array"> <policy> <policyType>Mitsubishi</policyType> <policyNumber>17-516-9783</policyNumber> </policy> </policies> <policies datatype="array"> <policy> <policyType>Subaru</policyType> <policyNumber>71-370-4976</policyNumber> </policy> </policies>
相关配置
实体描述文件 - policies数组定义
<policies> <es:datatype>array</es:datatype> <es:items><es:ref>#/definitions/policy</es:ref></es:items> </policies>
实体描述文件 - policy定义
<policy> <es:properties> <policyType> <es:datatype>string</es:datatype> <es:facetable>false</es:facetable> <es:sortable>false</es:sortable> <es:collation>http://marklogic.com/collation/codepoint</es:collation> </policyType> <policyNumber> <es:datatype>string</es:datatype> <es:facetable>false</es:facetable> <es:sortable>false</es:sortable> <es:collation>http://marklogic.com/collation/codepoint</es:collation> </policyNumber> <policyZip> <es:datatype>string</es:datatype> <es:facetable>false</es:facetable> <es:sortable>false</es:sortable> <es:collation>http://marklogic.com/collation/codepoint</es:collation> </policyZip> </es:properties> </policy>
转换文件代码片段
let $policies := es:extract-array($source-node/policies, auto:extract-instance-policy#1)
auto:extract-instance-policy函数
declare function auto:extract-instance-policy( $source as item()? ) as map:map { let $source-node := es:init-source($source, 'policy') let $policyType := $source-node/make[not(. instance of null-node())] ! xs:string(.) let $policyNumber := $source-node/number[not(. instance of null-node())] ! xs:string(.) let $policyZip := $source/addrZip[not(. instance of null-node())] ! xs:string(.) let $instance := es:init-instance($source-node, 'policy') =>es:add-attachments($source) return if (empty($source-node/*)) then $instance else $instance =>es:optional('policyType', $policyType) =>es:optional('policyNumber', $policyNumber) =>es:optional('policyZip', $policyZip) };
源数据示例
{ "addrCity": "Wilkes Barre", "addrState": "PA", "addrStreet": "21156 Alpine Terrace", "addrZip": "18706", "birthDate": "10/19/1977", "email": "yfridayeqz@e-recht24.de", "ssn": "827-54-4139", "policies": [ { "make": "Mercedes-Benz", "model": "E-Class", "number": "40-294-9278", "vin": "WA1VKAFP6AA688103", "year": 2008 }, { "make": "Mitsubishi", "model": "Lancer", "number": "17-516-9783", "vin": "WBAPK5C51AA695692", "year": 2009 }, { "make": "Subaru", "model": "XT", "number": "71-370-4976", "vin": "WA1CGAFP1EA477275", "year": 1989 } ] }
问题分析与解决方案
核心问题
- policyZip取值错误:源数据中
addrZip属于根节点,而非单个policy对象,当前函数中$source是数组内的单个policy对象,无法通过$source/addrZip获取到值,导致输出缺失policyZip元素。 - 数组属性处理不当:将提取后的policy数组添加到主实体时,未使用数组专属的添加方法,导致每个policy被封装为独立的
<policies>节点,而非合并到同一个数组节点下。
解决方案
1. 修复policyZip取值逻辑
修改auto:extract-instance-policy函数,新增参数接收根节点的addrZip值,确保每个policy能正确获取到该值:
declare function auto:extract-instance-policy( $source as item()?, $parent-addrZip as xs:string? ) as map:map { let $source-node := es:init-source($source, 'policy') let $policyType := $source-node/make[not(. instance of null-node())] ! xs:string(.) let $policyNumber := $source-node/number[not(. instance of null-node())] ! xs:string(.) let $policyZip := $parent-addrZip let $instance := es:init-instance($source-node, 'policy') =>es:add-attachments($source) return if (empty($source-node/*)) then $instance else $instance =>es:optional('policyType', $policyType) =>es:optional('policyNumber', $policyNumber) =>es:optional('policyZip', $policyZip) };
同步修改es:extract-array的调用代码,传递根节点的addrZip:
let $addrZip := $source-node/addrZip ! xs:string(.) let $policies := es:extract-array($source-node/policies, function($item) { auto:extract-instance-policy($item, $addrZip) })
2. 正确添加数组属性到主实体
构建主实体时,使用es:add-array方法将整个policy数组添加为单个属性,避免生成多个<policies>节点:
let $main-instance := es:init-instance($source-node, 'person') // 添加其他主实体属性,比如addrZip、email等 =>es:add-optional('addrZip', $addrZip) =>es:add-optional('email', $source-node/email ! xs:string(.)) // 将policy数组添加为单个属性 =>es:add-array('policies', $policies)
3. 正确序列化实体为XML
使用es:instance-to-xml函数将实体实例序列化为XML,该函数会自动将数组类型属性转换为单个父节点包含多个子元素的结构:
es:instance-to-xml($main-instance)
内容的提问来源于stack exchange,提问作者Thierry Bordet
相关产品推荐
相关产品推荐

