XSLT doc(uri) or document(uri) function not resolving uri in context of content database?

冷暖自知 提交于 2020-07-22 22:13:37

问题


Working with latest MarkLogic-10.0-2.1-amd64 on win10

In a xquery I invoke an xslt transformation:

xdmp:xslt-invoke("/tidy2html.xslt", doc($docurl))

And within that xslt transformation, I want to retrieve an additional doc (with uri sdp/xref.xml) from the content database where $docurl resides.

<xsl:variable name="xref-uri" select="doc('sdp/xref.xml')"/>

I'm sure by looking at query console that doc('sdp/xref.xml') exists using XQuery context pointed to the content database.

In XSLT I'm a bit lost since doc('sdp/xref.xml') returns nothing, making me believe that we might be module database context where the xslt is stored, rather than content database context which I expect to be in.

Is there any way I can fetch (/debug) xslt resolution of doc('sdp/xref.xml')?

I have looked into document() and that didn't bring me closer to a solution. And the stylesheet does work when its applied on a local file system using saxon XSLT.


回答1:


Try document('sdp/xref.xml', /) instead of the doc call you have.




回答2:


As workaround I call doc() on XQuery side and pass it along.

let $tocurl := 'sdp/xref.xml'
let $params := map:map()
let $_put := map:put($params, "xref", doc($tocurl))
return
    xdmp:xslt-invoke("/tidy2html.xslt", doc($docurl), $params)

Then in XSLT, pick up the xref

<xsl:stylesheet version="3.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
  ...>
    <xsl:param name="xref" as="node()*"/>
    <!-- $xref contains doc('sdp/xref.xml') -->

This works.




回答3:


Use the option database to force the content database used during evaluating the XSLT:

xdmp:xslt-invoke(
  '/some/stylesheet.xsl',
  <input/>,
  <options xmlns="xdmp:eval">
    <database>{ xdmp:database('content-db') }</database>
  </options>)

If you want to gather more information, you can use the following in the invoking XQuery to double-check which content DB is used:

xdmp:database-name(xdmp:database())

You can also use this (or plug the xsl:value-of somehow in your stylesheet) to double-check the content DB used for evaluating the stylesheet, and the number of documents it contains:

xdmp:xslt-eval(
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                  xmlns:xdmp="http://marklogic.com/xdmp"
                  version="2.0">
    <xsl:template match="node()">
      <response>
        <database>
          <xsl:value-of select="xdmp:database-name(xdmp:database())"/>
        </database>
        <count>
          <xsl:value-of select="xdmp:estimate(collection())"/>
        </count>
      </response>
    </xsl:template>
  </xsl:stylesheet>,
  <placeholder/>)

And to ensure that the return of doc() is indeed empty, use the as attribute on your xsl:variable:

<xsl:variable name="xref-uri" select="doc('sdp/xref.xml')" as="node()"/>



回答4:


Using fn:doc inside XSLT works just as you'd expect inside MarkLogic. I suspect something else went wrong with your $xref-uri variable. No need to pass the entire document through as param:

xquery version "1.0-ml";

let $uri := cts:uris()[1]
return
  xdmp:xslt-eval(
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:param name="uri"/>
      <xsl:template match="/">
        <xsl:sequence select="doc($uri)"/>
      </xsl:template>
    </xsl:stylesheet>,
    document{ "" },
    map:entry("uri", $uri)
  )

HTH!




回答5:


Did some further investigations on my question, tested both xdmp:xslt-invoke and xdmp:xslt-eval

xdmp:xslt-invoke

Given: test-xslt.xqy

xquery version "1.0-ml";
let $xref := doc('sdp/xref.xml')
return
  xdmp:xslt-invoke(
    '/test-xslt.xslt',
    <dummy/>,
    map:entry("xref-param", $xref)
  )

Calling test-xslt.xslt:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xdmp="http://marklogic.com/xdmp" version="2.0" xmlns="http://ing.com/vortex/sql/grammar">
    <xsl:param name="xref-param" as="document-node()?"/>
    <xsl:template match="node()">
        <response>
            <database>
                <xsl:value-of select="xdmp:database-name(xdmp:database())"/>
            </database>
            <count>
                <xsl:value-of select="xdmp:estimate(collection())"/>
            </count>
            <case name="internal doc">
                <xsl:variable name="xref" select="doc('sdp/xref.xml')" as="document-node()?"/>
                <xsl:choose>
                    <xsl:when test="empty($xref)">
                        <empty-doc/>
                    </xsl:when>
                    <xsl:otherwise>
                        <content>
                            <xsl:copy-of select="$xref"/>
                        </content>
                    </xsl:otherwise>
                </xsl:choose>
            </case>
            <case name="doc from param">
                <xsl:choose>
                    <xsl:when test="empty($xref-param)">
                        <empty-doc/>
                    </xsl:when>
                    <xsl:otherwise>
                        <content>
                            <xsl:copy-of select="$xref-param"/>
                        </content>
                    </xsl:otherwise>
                </xsl:choose>
            </case>
        </response>
    </xsl:template>
</xsl:stylesheet>

I get results:

<response xmlns:xdmp="http://marklogic.com/xdmp" xmlns="http://ing.com/vortex/sql/grammar">
    <database>SqlXmlPub-content</database>
    <count>16968</count>
    <case name="internal doc">
        <empty-doc/>
    </case>
    <case name="doc from param">
        <content> 
            expected content
        </content>
    </case>
</response>

Observations:

  • xdmp:xslt-invoke keeps the right database being selected! (content rather than modules database)
  • Passing doc('sdp/xref.xml') from xq to xslt works fine
  • Resolving doc('sdp/xref.xml') within xslt called by xdmp:xslt-invoke doesn't work??

xdmp:xslt-eval

Given: test2-xslt.xqy

xquery version "1.0-ml";

let $xref := doc('sdp/xref.xml')
return
  xdmp:xslt-eval(
  <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xdmp="http://marklogic.com/xdmp" 
    xmlns="http://ing.com/vortex/sql/grammar"
    xmlns:f="http://ing.com/vortex/sql/functions">
    <xsl:import href="test-xslt.xslt"/>
    <xsl:param name="xref-param"/>
    <xsl:template match="node()">
        <results>
            <xsl:sequence select="f:test-doc(doc('sdp/xref.xml'), 'wrapper doc ref')"/>
            <xsl:sequence select="f:test-doc($xref-param, 'wrapper from param')"/>                       
            <xsl:call-template name="imported-context"/>
        </results>
    </xsl:template>
    <xsl:function name="f:test-doc">
        <xsl:param name="doc" as="node()*"/>
        <xsl:param name="name"/>
        <case name="{{$name}}" result="{{if (empty($doc)) then 'fail' else 'pass'}}"/>
    </xsl:function>    
  </xsl:stylesheet>,
    <dummy/>,
    map:entry("xref-param", $xref)
  )

And imported stylesheet test-xslt.xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xdmp="http://marklogic.com/xdmp" version="2.0" 
    xmlns="http://ing.com/vortex/sql/grammar"
    xmlns:f="http://ing.com/vortex/sql/functions">
    <xsl:param name="xref-param" as="document-node()?"/>
    <xsl:template name="imported-context">
        <response db="{xdmp:database-name(xdmp:database())}" est="{xdmp:estimate(collection())}">
            <xsl:sequence select="f:test-doc(doc('sdp/xref.xml'), 'substyle doc ref')"/>
            <xsl:sequence select="f:test-doc($xref-param, 'substyle from param')"/>                       
        </response>
    </xsl:template>
</xsl:stylesheet>

I get results:

<results xmlns:xdmp="http://marklogic.com/xdmp" xmlns="http://ing.com/vortex/sql/grammar"
    xmlns:f="http://ing.com/vortex/sql/functions">
    <case name="wrapper doc ref" result="pass"/>
    <case name="wrapper from param" result="pass"/>
    <response db="SqlXmlPub-content" est="16968">
        <case name="substyle doc ref" result="fail"/>
        <case name="substyle from param" result="pass"/>
    </response>
</results>

Observations:

  • the right content database is selected
  • in respect to doc() xdmp:xslt-eval has similar issues as xdmp:xslt-invoke. In a sub stylesheet doc() returns empty where some content is expected.

Wrap up

The samples provided by grtjn and Florent do work well and also helped me to analyse further. Would be nice if I can find a better workaround than passing the doc() as param to have access to uri referenced items in the content database. I wonder if this is a bug, for now I have a workaround. Thanks!



来源:https://stackoverflow.com/questions/59749472/xslt-docuri-or-documenturi-function-not-resolving-uri-in-context-of-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!