MarkLogic含空格与特殊字符的URI创建失败求助
问题:MarkLogic入库时URI转换后触发无效参数错误
创建了一个MarkLogic转换(transform),目的是在数据入库时转换URL编码的[]和空格字符,但处理后的URI被判定无效,触发500错误REST-INVALIDPARAM。
相关代码
XQuery转换代码
xquery version "1.0-ml"; module namespace space = "http://marklogic.com/rest-api/transform/space-to-space"; declare function space:transform( $context as map:map, $params as map:map, $content as document-node() ) as document-node() { let $puts := ( xdmp:log($params), xdmp:log($context), map:put($context, "uri", fn:replace(map:get($context, "uri"), "%5B+", "[")), map:put($context, "uri", fn:replace(map:get($context, "uri"), "%5D+", "]")), map:put($context, "uri", fn:replace(map:get($context, "uri"), "%20+", " ")), xdmp:log($context) ) return $content };
Python测试代码
def upload_document(self, inputContent, uri, fileType, database, collection): if fileType == 'XML': headers = {'Content-type': 'application/xml'} fileBytes = str.encode(inputContent) elif fileType == 'TXT': headers = {'Content-type': 'text/*'} fileBytes = str.encode(inputContent) else: headers = {'Content-type': 'application/octet-stream'} fileBytes = inputContent endpoint = ML_DOCUMENTS_ENDPOINT params = {} if uri is not None: encodedUri = urllib.parse.quote(uri) endpoint = endpoint + "?uri=" + encodedUri if database is not None: params['database'] = database if collection is not None: params['collection'] = collection params['transform'] = 'space-to-space' req = PreparedRequest() req.prepare_url(endpoint, params) response = requests.put(req.url, data=fileBytes, headers=headers, auth=HTTPDigestAuth(ML_USER_NAME, ML_PASSWORD)) print('upload_document result: ' + str(response.status_code)) if response.status_code == 400: print(response.text)
日志内容
- 2023-02-13 16:59:00.067 Info: {}
- 2023-02-13 16:59:00.067 Info:
{"input-type":"application/octet-stream",
"uri":"/Judgment/26856/supportingfiles/[TEST] 57_image1.PNG", "output-type":"application/octet-stream"} - 2023-02-13 16:59:00.067 Info:
{"input-type":"application/octet-stream",
"uri":"/Judgment/26856/supportingfiles/[TEST] 57_image1.PNG", "output type":"application/octet-stream"} - 2023-02-13 16:59:00.653 Info: Status 500: REST-INVALIDPARAM: (err:FOER0000)
Invalid parameter: invalid uri:
/Judgment/26856/supportingfiles/[TEST] 57_image1.PNG
问题分析
- Transform代码逻辑无效:REST API在调用transform前已经自动解码了uri参数,所以
fn:replace匹配不到%5B、%20这类编码字符,导致context中的uri没有被修改(日志显示处理前后uri一致)。 - URI合法性问题:MarkLogic的REST API不允许文档URI包含空格,因此解码后的带空格URI触发
REST-INVALIDPARAM错误。
解决方案
方案1:调整URI格式,替换空格为合法字符
如果不需要保留空格,修改transform将空格替换为下划线(MarkLogic允许[]在文档URI中):
xquery version "1.0-ml"; module namespace space = "http://marklogic.com/rest-api/transform/space-to-space"; declare function space:transform( $context as map:map, $params as map:map, $content as document-node() ) as document-node() { let $originalUri := map:get($context, "uri") -- 替换空格为下划线,保留[] let $newUri := fn:replace($originalUri, "\s", "_") let $_ := map:put($context, "uri", $newUri) let $_ := xdmp:log(xdmp:concat("Updated URI: ", $newUri)) return $content };
方案2:优化Python代码的URI处理
如果需要保留空格(确认MarkLogic版本支持),让prepare_url自动处理URI编码,移除transform中无效的替换逻辑:
def upload_document(self, inputContent, uri, fileType, database, collection): if fileType == 'XML': headers = {'Content-type': 'application/xml'} fileBytes = str.encode(inputContent) elif fileType == 'TXT': headers = {'Content-type': 'text/*'} fileBytes = str.encode(inputContent) else: headers = {'Content-type': 'application/octet-stream'} fileBytes = inputContent endpoint = ML_DOCUMENTS_ENDPOINT params = {} if uri is not None: params['uri'] = uri # 不手动编码,交给prepare_url自动处理 if database is not None: params['database'] = database if collection is not None: params['collection'] = collection params['transform'] = 'space-to-space' # 仅用于日志或其他非URI修改的处理 req = PreparedRequest() req.prepare_url(endpoint, params) response = requests.put(req.url, data=fileBytes, headers=headers, auth=HTTPDigestAuth(ML_USER_NAME, ML_PASSWORD)) print('upload_document result: ' + str(response.status_code)) if response.status_code == 400: print(response.text)
方案3:直接用XQuery插入文档(绕过REST API限制)
如果必须保留空格和[]作为URI,可直接调用XQuery的xdmp:document-insert插入,避免REST API的URI验证:
xquery version "1.0-ml"; declare variable $uri as xs:string external; declare variable $content as document-node() external; xdmp:document-insert($uri, $content);
通过Python调用MarkLogic的XQuery执行端点运行这段代码即可。
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

