I have schematron file which contains xsl function.
I get this error : "the function functionName was not found in namespace localFunctions"
Here is my schematron codes:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fct="localFunctions"
queryBinding="xslt2" >
<ns prefix="gl-plt" uri="http://www.xbrl.org/int/gl/plt/2010-04-16" />
<ns prefix="gl-cor" uri="http://www.xbrl.org/int/gl/cor/2006-10-25" />
<ns prefix="gl-bus" uri="http://www.xbrl.org/int/gl/bus/2006-10-25" />
<ns prefix="xbrli" uri="http://www.xbrl.org/2003/instance" />
<ns prefix="edefter" uri="http://www.edefter.gov.tr" />
<ns prefix="fct" uri="localFunctions" />
<title></title>
<!-- <gl-cor:accountingEntries> elemanı bir <gl-cor:entityInformation> elemanı içermelidir. -->
<pattern id="accountingentries">
<rule context="/edefter:defter/xbrli:xbrl/gl-cor:accountingEntries">
<let name="accoundMainIdList" value="gl-cor:entryHeader/gl-cor:entryDetail[1]/gl-cor:account/normalize-space(gl-cor:accountMainID)"/>
<assert test="fct:isSorted($accoundMainIdList)">Büyük defterde hesaplar, ana hesap numarası bazında sıralı olmalıdır.</assert>
</rule>
</pattern>
<xsl:function name="fct:isSorted" as="xs:boolean">
<xsl:param name="accoundMainIdList" as="xs:string*"/>
<xsl:variable name="sortedAccountMainIdList" as="xs:string*">
<xsl:for-each select="$accoundMainIdList">
<xsl:sort/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="s1">
<xsl:value-of select="string-join($accoundMainIdList,'|')"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:value-of select="string-join($sortedAccountMainIdList,'|')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$s1 = $s2">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</schema>
Why isSorted xsl function not found in namespace ?
I'm assuming that you are aware that the conventional method of running Schematron schemas is to process them using XSLT to generate an XSLT stylesheet which can be executed against your XML instance.
Looking on github, the XRouters Schematron projects is using a very old version of the standard XSLT stylesheets from http://www.schematron.com/. These are XSLT 1.0 stylesheets and are not capable of generating XSLT 2.0 stylseheets.
The xsl:function element you are trying to use is part of XSLT 2.0. Given that your tool is generating XSLT 1.0 it seems very unlikely that your XSLT 2.0 function will operate.
If you want to try an approach that may be more successful, may I suggest that you obtain a copy of Saxon HE (the .net version) from http://saxon.sf.net/. You can then build a simple set of XSLT transforms that will give you more of a chance of getting what you want.
I think #Nic's answer is in the right direction, but missed the mark.
Although the standard way of running schematron schemas against XML documents is to convert them to XSLT, that approach has a number of drawbacks (speed and having validation report you can process programmatically are two primary ones).
The XRouter SchemaTron is a native .NET implementation of ISO schematron. It doesn't convert the schematron schemas to XSLT stylesheets -- it parses them in memory and then processes each pattern/rule/assert to detect violations.
The problem is certainly rooted in a lack of XSLT2 support, but is not related at all to XSLT schematron stylesheets (they arent used, and are included in the project only as reference). Schematron specification doesn't require XSLT2 (or XPATH2) -- it leaves the query language to the schematron rules file. The branch you were using was probably the one delivering XPATH2 support via "Lightweight XPath2 for .NET", which doesn't support XSLT2.
I recommend using the branch of the project integrated with XmlPrime, with supports XSLT2. We're using that version with great success.
Related
I've been trying to figure out a way to use a param/variable as an argument to a function.
At the very least, I'd like to be able to use basic string parameters as arguments as follows:
<xsl:param name="stringValue" default="'abcdef'"/>
<xsl:value-of select="substring(string($stringValue),1,3)"/>
The above code generates no output.
I feel like I'm missing a simple way of doing this. I'm happy to use exslt or some other extension if an xslt 1.0 processor does not allow this.
Edit:
I am using XSL 1.0 and transforming using Nokogiri, which supports XPATH 1.0 . Here is a more complete snippet of what I am trying to do:
I want to pass column numbers as parameters using nokogiri as follows
document = Nokogiri::XML(File.read('table.xml'))
template = Nokogiri::XSLT(File.read('extractTableData.xsl'))
transformed_document = template.transform(document,
["tableName","'Problems'", #Table Heading
"tablePath","'Table'", #Takes an absolute XPATH String
"nameColumnIndex","2", #column number
"valueColumnIndex","3"]) #column number
File.open('FormattedOutput.xml', 'w').write(transformed_document)
My xsl then wants to access every TD[valueColumnIndex] and and retrieve the first 3 characters at that position, which is why I am using a substring function. So I want to do something like:
<xsl:value-of select="substring(string(TD[$valueColumnIndex]),1,3)"/>
Since I was unable to do that, I tried to extract TD[$valueColumnIndex] to another param valueCode and then do substring(string(valueCode),1,3)
That did not work either (which is to say, no text was output, whereas <xsl:value-of select="$valueCode"/> gave me the expected output).
As a result, i decided to understand how to use parameters better, I would just use a hard coded string, as mentioned in my earlier question.
Things I have tried:
using single quotes around abcdef (and not) while
using string() around the param name (and not)
Based on the comments below, it seems I am handicapped in my ability to understand the error because Nokogiri does not report an error for these situations. I am in the process of installing xsltproc right now and seeing if I receive any errors.
Finally, here is my entire xsl. I use a separate template forLoop because of the valueCode param I am creating. The lines of interest are the last 5 or so. I cannot include the xml as there are data use issues involved.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
exclude-result-prefixes="ext dyn">
<xsl:param name="tableName" />
<xsl:param name="tablePath" />
<xsl:param name= "nameColumnIndex" />
<xsl:param name= "valueColumnIndex"/>
<xsl:template match="/">
<xsl:param name="tableRowPath">
<xsl:value-of select="$tablePath"/><xsl:text>/TR</xsl:text>
</xsl:param>
<!-- Problems -->
<section>
<name>
<xsl:value-of select="$tableName" />
</name>
<!-- <xsl:for-each select="concat($tablePath,'/TR')"> -->
<xsl:for-each select="dyn:evaluate($tableRowPath)">
<!-- Encode record section -->
<xsl:call-template name="forLoop"/>
</xsl:for-each>
</section>
</xsl:template>
<xsl:template name="forLoop">
<xsl:param name="valueCode">
<xsl:value-of select="./TD[number($valueColumnIndex)][text()]"/>
</xsl:param>
<xsl:param name="RandomString" select="'Try123'"/>
<section>
<name>
<xsl:value-of select="./TD[number($nameColumnIndex)]"/>
</name>
<code>
<short>
<xsl:value-of select="substring(string($valueCode),1,3)"/>
</short>
<long>
<xsl:value-of select="$valueCode"/>
</long>
</code>
</section>
</xsl:template>
</xsl:stylesheet>
Use it this way:
<xsl:param name="stringValue" select="'abcdef'"/>
<xsl:value-of select="substring($stringValue,1,3)"/>
<xsl:variable name="dictFile" select="document('dictionary.xml')" />
<xsl:key name="lookupTable" match="$dictFile/dictionary/item" use="#name" />
<xsl:variable name="lookup1" select="key('lookupTable','lookupA')" />
<xsl:variable name="lookup2" select="key('lookupTable','lookupB')" />
This does not compile with Saxon 9.5 EE returning an error:
XTSE0340 XSLT Pattern syntax error at char 0 on line 55 in {$dictFile}:
A variable reference is not allowed in an XSLT pattern (except in a predicate)
Unfortunately, I need to keep those variables lookup1 and lookup2 defined as they are. I would like to change as little code here as possible. It is a very old and large codebase running on a custom enterprise XSL engine that supports these kinds of constructs .
The right way in standard XSLT 2.0 would be
<xsl:variable name="dictFile" select="document('dictionary.xml')" />
<xsl:key name="lookupTable" match="dictionary/item" use="#name" />
<xsl:variable name="lookup1" select="key('lookupTable','lookupA', $dictFile)" />
<xsl:variable name="lookup2" select="key('lookupTable','lookupB', $dictFile)" />
This exact scenario is discussed in the XSLT 2.0 specification and two solutions are offered (scroll down to the Example: Using Keys to Reference other Documents part).
I need the following output for bizzare system which expects same xmlns declared in parent and child and refuses to work otherwise. I.e that's what expected:
<root xmlns="http://something">
<element xmlns="http://something" />
</root>
I can create xmlns in root with
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:element name="root" namespace="http://something">
<xsl:element name="node" namespace="http://something" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
However it doesn't add xmlns into childnode because node's parent has the same xmlns. How to force XSLT to write xmlns disregarding parent?
The XML schema specification expressly prohibits attributes named xmlns, so an XSLT stylesheet cannot create such attributes directly using <xsl:attribute>. I can only see two options for you...
One option is to create dummy attributes using a different name (e.g. xmlnsx):
<xsl:template match="/">
<xsl:element name="root">
<xsl:attribute name="xmlnsx">http://something</xsl:attribute>
<xsl:element name="node">
<xsl:attribute name="xmlnsx">http://something</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
... and then replace all occurrences of the attribute xmlnsx with xmlns in some post-processing step (such as a SAX filter or other stream editor). However, this solution involves inserting a non-XSLT step into the pipeline.
The other option is pure, if ugly, XSLT. You could generate the required XML directly, using xsl:text and disable-output-escaping, like this:
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><root xmlns="http://something"></xsl:text>
<xsl:text disable-output-escaping="yes"><node xmlns="http://something"></xsl:text>
<xsl:text disable-output-escaping="yes"></root></xsl:text>
</xsl:template>
Note that the XSLT 1.0 specification is pretty loose when it comes to serialization, so a particular XSLT processor could still conceivable strip the redundant namespace declarations from this second solution. However, it worked in the four processors that I tried (namely Saxon, MSXML, MSXML.NET and LIBXML).
I'm transforming an XML Schema using XSLT 2.0. The first schema (s1.xsd) imports a second schema (s2.xsd) as follows:
Content of s1.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd"
xmlns:ns1="URI1" targetNamespace="URI2"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<import namespace="URI1" schemaLocation="s2.xsd"/>
<element name="element1"/>
<element name="element2"/>
</schema>
and content of s2.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ns1="URI1" targetNamespace="URI1">
<attribute name="attr1"/>
<schema>
My XSLT declares the XS namespace as follows:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
I would like to merge the nodes of s2.xsd into the <schema>-element of s1.xsd. So far, I've tried
<xsl:template name="merge_imported_schemas">
<xsl:for-each select="/schema/import[#namespace = //namespace::*]">
<!-- file exists? -->
<xsl:choose>
<xsl:when test="boolean(document(#schemaLocation))">
<!-- schema found -->
<xsl:copy-of select="document(#schemaLocation)/*/node()"/>
</xsl:when>
<xsl:otherwise>
<!-- schema not found -->
<xsl:message terminate="yes">
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
but I don't get the desired result. Could anyone please tell me what I'm doing wrong? I suspect there is a namespace-collision here, but honestly I find using namespaces a little confusing. Thanks!
You need to qualify the elements in your XPath. At the moment select="/schema/import[#namespace = //namespace::*]"> doesn't match anything at all, because there is no element /schema. The XPath is trying to match elements with no namespace.
Change it to select="/xs:schema/xs:import[#namespace = //namespace::*]"> and it should work.
Remember, namespace prefixes are an alias for the namespace URI, and if you have a default namespace (as in your xsd files), elements with no prefix are still namespace-qualified.
As an aside, instead of <xsl:for-each select="/schema/import[#namespace = //namespace::*]">, you might have more success using <xsl:apply-templates select="/xs:schema/node()", and defining different templates for the different kinds of node that you wish to copy into the output tree.
I have a page which has URL structure :
http://www.abc.com/xyz?parama=1¶mb=2
Is is possible to create a generic method for getting the values of any additional params the URL maybe (parama=1¶mb=2)
Is is possible to get the URL of the page in XSL similar to javascript's location.href ?
Is is possible to get the URL of the page in XSL similar to javascript's location.href ?
Not exactly in the same way, but yes, the query string can be passed as a parameter.
Is is possible to create a generic
method for getting the values of any
additional params the URL maybe
(parama=1¶mb=2)
Yes, one can perform tokenization (with the tokenize() function in XSLT 2.0 or in XSLT 1.0 using the str-split-to-words template of **FXSL 1.x or a self-written recursive tokenization template.)
XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
>
<xsl:import href="strSplit-to-Words.xsl"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="pQString" select=
"'?parama=1¶mb=2&anyParamName=AnyValue'"
/>
<xsl:template match="/">
<xsl:variable name="vwordNodes">
<xsl:call-template name="str-split-to-words">
<xsl:with-param name="pStr" select="$pQString"/>
<xsl:with-param name="pDelimiters"
select="'?&'"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vwordNodes)/*
"/>
</xsl:template>
<xsl:template match="word">
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
when the above transformation is applied on any XML document (will not be used), the wanted result is produced:
parama=1
paramb=2
anyParamName=AnyValue
Do note the use of the FXSL 1.x str-split-to-words template and the use of the EXSLT ext:node-set() extension function.
XSLT 2.0 solution:
<xsl:param name="pQString" as="xs:string" select=
"'?parama=1¶mb=2&anyParamName=AnyValue'"
/>
<xsl:template match="/">
<xsl:value-of separator="
" select=
"tokenize($pQString, '\?|&')
"/>
</xsl:template>
When the above XSLT 2.0 transformation is performed, it produces the correct result:
parama=1
paramb=2
anyParamName=AnyValue
This might be possible using EXSLT, or registering a function callback with your particular xslt processor, but not with plain old XSLT, at least not to my knowledge. With plain XSLT, if it isn't in the XML, then it doesn't exist.
If it is client side, there isn't any way of doing this. Unfortunately, xsl is very limited in the browser. I'm afraid you will need to move the functionality to the webapp or to javascript.
If the transform is server side, there might be something you can do.
I workaround this by using javascript in mi XSLT file. take a look.
on The XML I have a tag element named tag! yes, very original...
<tag url="http://www.demo.net/share.php?u=param1 />
Mi Sample transform
<div class="HelloDiv">
<xsl:for-each select="tag">
<a href="{#url}">
This is my custom URL
</a>
</xsl:for-each>
</div>
Now inside the template of the transform, in going to load my custom value in Param1
in this case i'm going to use the document.title.. by using a jquery function.
<script type="text/javascript">
jQuery(function(){
jQuery('div.HelloDiv a').each(function(){
var parameter = jQuery(this).attr('href');
parameter = currentUrl.replace('param1',escape(document.title));
jQuery(this).attr('href',parameter);
})
});
</script>