上传至MarkLogic时如何强制指定XML contentType?
我通过自制HTTP服务器上传带有明确.xml扩展名的文件,但MarkLogic却在本地数据库中将其保存为.txt文件,导致无法执行XML相关查询。
我的上传XQuery函数如下:
declare function local:uploadFile() { let $filename := xdmp:get-request-field-filename("upload") let $file := xdmp:get-request-field("upload") let $collection := "semansysdocs" return xdmp:document-insert( $filename, $file, xdmp:default-permissions(), (xdmp:default-collections(), $collection) ) };
示例上传文档(文件名:Prod223_1982_03975172_20170430.xml):
<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="http://www.companieshouse.gov.uk/ef/xbrl/uk/fr/gaap/ae/2009-06-21/stylesheet/CH-AE-dormant-stylesheet.xsl"?> <xbrl xmlns="http://www.xbrl.org/2003/instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ae="http://www.companieshouse.gov.uk/ef/xbrl/uk/fr/gaap/ae/2009-06-21" xmlns:gc="http://www.xbrl.org/uk/fr/gcd/2004-12-01" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:iso4217="http://www.xbrl.org/2003/iso4217" xmlns:link="http://www.xbrl.org/2003/linkbase" xmlns:pt="http://www.xbrl.org/uk/fr/gaap/pt/2004-12-01" xmlns:xbrli="http://www.xbrl.org/2003/instance" xmlns:xlink="http://www.w3.org/1999/xlink"> <link:schemaRef xlink:arcrole="http://www.w3.org/1999/xlink/properties/linkbase" xlink:href="http://www.companieshouse.gov.uk/ef/xbrl/uk/fr/gaap/ae/2009-06-21/uk-gaap-ae-2009-06-21.xsd" xlink:type="simple"/> <ae:CompanyDormant contextRef="y2017">true</ae:CompanyDormant> <gc:EntityNames> <gc:EntityCurrentLegalName contextRef="y2017">HUNTS GROUP PLC</gc:EntityCurrentLegalName> </gc:EntityNames> <ae:CompanyIdentifyingNumbers> <ae:CompaniesHouseRegisteredNumber contextRef="y2017">03975172</ae:CompaniesHouseRegisteredNumber> </ae:CompanyIdentifyingNumbers> <gc:StatementDatesPeriodsCovered> <gc:BalanceSheetDate contextRef="e2017">2017-04-30</gc:BalanceSheetDate> </gc:StatementDatesPeriodsCovered> <pt:ShareholderFunds precision="6" contextRef="e2017" unitRef="GBP">12500</pt:ShareholderFunds> <pt:ShareholderFunds precision="6" contextRef="e2016" unitRef="GBP">12500</pt:ShareholderFunds> <pt:NetAssetsLiabilitiesIncludingPensionAssetLiability precision="5" contextRef="e2017" unitRef="GBP">12500</pt:NetAssetsLiabilitiesIncludingPensionAssetLiability> <pt:NetAssetsLiabilitiesIncludingPensionAssetLiability precision="5" contextRef="e2016" unitRef="GBP">12500</pt:NetAssetsLiabilitiesIncludingPensionAssetLiability> <pt:CashBankInHand precision="5" contextRef="e2017" unitRef="GBP">12500</pt:CashBankInHand> <pt:CashBankInHand precision="5" contextRef="e2016" unitRef="GBP">12500</pt:CashBankInHand> <pt:EquityAuthorisedDetails> <pt:TypeOrdinaryShare contextRef="y2017">Ordinary</pt:TypeOrdinaryShare> <pt:NumberOrdinarySharesAuthorised precision="INF" contextRef="e2017" unitRef="shares">50000</pt:NumberOrdinarySharesAuthorised> <pt:ParValueOrdinaryShare precision="INF" contextRef="y2017" unitRef="GBP">1</pt:ParValueOrdinaryShare> </pt:EquityAuthorisedDetails> <pt:DetailsOrdinarySharesAllotted> <pt:TypeOrdinaryShare contextRef="y2017">Ordinary</pt:TypeOrdinaryShare> <pt:ParValueOrdinaryShare precision="INF" contextRef="y2017" unitRef="GBP">1</pt:ParValueOrdinaryShare> <pt:ValueOrdinarySharesAllotted precision="5" contextRef="e2017" unitRef="GBP">12500</pt:ValueOrdinarySharesAllotted> <pt:ValueOrdinarySharesAllotted precision="5" contextRef="e2016" unitRef="GBP">12500</pt:ValueOrdinarySharesAllotted> <pt:NumberOrdinarySharesAllotted precision="INF" contextRef="e2017" unitRef="shares">12500</pt:NumberOrdinarySharesAllotted> </pt:DetailsOrdinarySharesAllotted> <pt:DateApproval contextRef="e2017">2017-10-13</pt:DateApproval> <pt:ApprovalDetails> <pt:NameApprovingDirector contextRef="y2017">Mr. David Charles Hunt</pt:NameApprovingDirector> </pt:ApprovalDetails> <ae:CompanyEntitledToExemptionUnderSection480CompaniesAct2006 contextRef="y2017">true</ae:CompanyEntitledToExemptionUnderSection480CompaniesAct2006> <ae:MembersHaveNotRequiredCompanyToObtainAnAudit contextRef="y2017">true</ae:MembersHaveNotRequiredCompanyToObtainAnAudit> <ae:DirectorsAcknowledgeTheirResponsibilitiesUnderCompaniesAct contextRef="y2017">true</ae:DirectorsAcknowledgeTheirResponsibilitiesUnderCompaniesAct> <ae:AccountsAreInAccordanceWithSpecialProvisionsCompaniesActRelatingToSmallCompanies contextRef="y2017">true</ae:AccountsAreInAccordanceWithSpecialProvisionsCompaniesActRelatingToSmallCompanies> <unit id="shares"> <measure>xbrli:shares</measure> </unit> <unit id="GBP"> <measure>iso4217:GBP</measure> </unit> <unit id="pure"> <measure>xbrli:pure</measure> </unit> <context id="y2017"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <startDate>2016-05-01</startDate> <endDate>2017-04-30</endDate> </period> </context> <context id="y2016"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <startDate>2015-05-01</startDate> <endDate>2016-04-30</endDate> </period> </context> <context id="s2016"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <instant>2015-04-30</instant> </period> </context> <context id="e2016"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <instant>2016-04-30</instant> </period> </context> <context id="s2017"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <instant>2016-04-30</instant> </period> </context> <context id="e2017"> <entity> <identifier scheme="/results">HUNTS GROUP PLC</identifier> </entity> <period> <instant>2017-04-30</instant> </period> </context> <ae:CompaniesHouseDocumentAuthentication contextRef="y2017"></ae:CompaniesHouseDocumentAuthentication> <ae:DateAccountsReceived contextRef="e2017">2017-10-16</ae:DateAccountsReceived> </xbrl>
这是一份XBRL文档(属于XML的扩展格式),但我没法在xdmp:document-insert()里直接指定contentType,请问有什么办法能强制设置它的XML contentType?
解决方案
这个问题的核心是你现在插入的是字符串类型的内容,MarkLogic会默认把字符串识别为text/plain类型,哪怕文件名带.xml扩展名也没用。下面有几个靠谱的解决办法:
1. 将上传内容解析为XML节点后插入
直接把$file从字符串转换成XML节点,这样MarkLogic会自动识别为XML类型,不需要额外指定contentType。修改你的函数:
declare function local:uploadFile() { let $filename := xdmp:get-request-field-filename("upload") let $file := xdmp:get-request-field("upload") let $xml-content := fn:parse-xml($file) <!-- 关键:把字符串解析成XML节点 --> let $collection := "semansysdocs" return xdmp:document-insert( $filename, $xml-content, <!-- 插入节点而非字符串 --> xdmp:default-permissions(), (xdmp:default-collections(), $collection) ) };
注意:如果上传的XML格式不合法,fn:parse-xml()会抛出错误,你可以考虑用try/catch来处理异常情况。
2. 使用xdmp:document-insert的选项参数设置contentType
MarkLogic的xdmp:document-insert支持第五个参数作为选项,你可以通过xdmp:document-insert-options()来指定contentType。修改后的函数:
declare function local:uploadFile() { let $filename := xdmp:get-request-field-filename("upload") let $file := xdmp:get-request-field("upload") let $collection := "semansysdocs" let $options := xdmp:document-insert-options( <options xmlns="xdmp:document-insert"> <content-type>application/xml</content-type> </options> ) return xdmp:document-insert( $filename, $file, xdmp:default-permissions(), (xdmp:default-collections(), $collection), $options <!-- 添加选项参数 --> ) };
这个方法适合你不想解析XML(比如担心解析错误),但又要强制设置contentType的场景。
3. 插入后更新文档的metadata
如果已经有大量错误类型的文档,或者你需要批量修正,可以用xdmp:document-set-properties来更新已插入文档的contentType属性:
xdmp:document-set-properties( "/path/to/your/document.xml", <properties xmlns="http://marklogic.com/xdmp/document"> <content-type>application/xml</content-type> </properties> )
不过更推荐在插入时就处理好,避免后续的批量操作。
内容的提问来源于stack exchange,提问作者Mick Remmerswaal

