You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

日志内容

  1. 2023-02-13 16:59:00.067 Info: {}
  2. 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"}
  3. 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"}
  4. 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

问题分析

  1. Transform代码逻辑无效:REST API在调用transform前已经自动解码了uri参数,所以fn:replace匹配不到%5B、%20这类编码字符,导致context中的uri没有被修改(日志显示处理前后uri一致)。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:06:56