问题
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 byxdmp: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 asxdmp:xslt-invoke
. In a sub stylesheetdoc()
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