Is there a way to get the current folder path from within a XSLT file?
I need it to locate other XML and XSLT files. We have different customer folders and will need to successfully find the correct files.
You can send it into the style-sheet from outside using xsl:param. Then you need to determine what the current path is when invoking the from the outside ;)
In MSXSL on Windows, you can use a script extension like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://tempuri.org/msxsl"
>
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
var fso = new ActiveXObject("Scripting.FileSystemObject");
function getCurrentPath(){
return fso.GetFolder(".").Path
}
]]>
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:getCurrentPath()"/>
</xsl:template>
</xsl:stylesheet>
Other XSL processors support similar methods to use external resources (scripting languages, function libraries etc.), so this is just an example.
Is there a way to get the current
folder path from within a xslt file?
Need it to locate other xml and xslt
files
No need for any extension functions or even parameters to do that!
Any relative URLs used in the href attribute of an <xsl:import> or <xsl:include>
instruction are resolved based on the URL of the current XSLT stylesheet -- it only needs to have an URL, which is vlearly stated as true in the question above. This is very convenient in importing/including XSLT stylesheets.
The document() function also will resolve a relative URL in a similar way, thus making any additional XML document accessible using anrelative URL.
Lastly, here is an example how this facilities are massively used in a big library of XSLT functions and templates (FXSL 2.x):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs xdt f"
>
<!--
This module contains the FXSL versions of the "standard" XPath functions
These are intended as convenience functions, so that they can be passed
as parameters to other functions (e.g. to f:zipWith())
or curried and passed as parameters (e.g. to f:map())
-->
<xsl:import href="func-curry.xsl"/>
<xsl:import href="func-compose-flist.xsl"/>
<xsl:import href="func-standardArithmeticXpathFunctions.xsl"/>
<xsl:import href="func-standardBooleanXpathFunctions.xsl"/>
<xsl:import href="func-standardStringXpathFunctions.xsl"/>
<xsl:import href="func-standardNodesXpathFunctions.xsl"/>
<xsl:import href="func-standardSequencesXpathFunctions.xsl"/>
<xsl:import href="func-standardAggregateXpathFunctions.xsl"/>
<xsl:import href="func-standardDateTimeXpathFunctions.xsl"/>
<xsl:import href="func-standardXSLTXpathFunctions.xsl"/>
<xsl:import href="func-standardAxisXpathFunctions.xsl"/>
</xsl:stylesheet>
This may work for your setup:
<xsl:value-of select="system-property('user.dir')"/>
For example,
<xsl:value-of select="document(concat(system-property('user.dir'),'/',filename,'.xml'))//title[1]"/>
no...
but you could maybe workaround the problem by using relative URLs and/or passing parameters into the stylesheet.
In most XSLT processor, you can add custom functions as extensions. For example here is Saxon's documentation how to do that.
Not AFAIK (though you could always pass it as a param to the transform), but I'm not clear why relative paths won't work for you here.
Related
I use an XSLT crosswalk to transform our standard in-house metadata XML to PBCore.
My prologue at the top of the xslt looks like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="MediaAsset">
<pbcoreCollection
xmlns="http://www.pbcore.org/PBCore/PBCoreNamespace.html"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.pbcore.org/PBCore/PBCoreNamespace.html
http://pbcore.org/xsd/pbcore-2.0.xsd">
Now I have a client asking for our PBCore metadata to be added to their own MODS metadata that they provide to us. I know that to properly next our PBCore within their MODS, all my tags have to have a pbcore: prefix. So my question is: how do I adapt my PBCore XSLT that I run our standard XML through to include the prefix in the output file? If I can do that then I can just copy the PBCore metadata and paste it into their MODs metadata, and just add
xmlns:pbcore="http://www.pbcore.org/PBCore/PBCoreNamespace.html"
xsi:schemaLocation="http://www.loc.gov/mods/v3
http://www.loc.gov/standards/mods/v3/mods-3-6.xsd
http://www.pbcore.org/PBCore/PBCoreNamespace.html
http://pbcore.org/xsd/pbcore-2.0.xsd">
to the prologue of the final output XML.
Rather than modifying your existing XSLT code, why not add another step to the pipeline that modifies the output of the existing stylesheet to meet the new requirements?
It's not entirely clear to me what the new requirements are. You talk about namespace prefixes needing to be changed, but generally speaking, namespace prefixes are purely cosmetic: it's namespace URIs that matter.
Some of my stylesheets are a bit large and some of their parts are repeating. I would like to use XInclude for them—which would allow me to separate them aside the whole stylesheet. I can’t use xsl:import or xsl:include here because I need to inject them into the specific place for generating bookmarks and active links (for XSL-FO).
If I use:
<xi:include href="/db/apps/tested-bunny/resources/xsl-fo/common/bookmark-tree.xml/>
… the .fo file produced really includes the part. However, the part is untranslated, which means it is there as is in the source. The XSL-FO processor thus ignores it and the pdf result is without bookmarks.
As for the separated part—I saved it as a regular XML file with two namespaces declared in the root element:
<fo:bookmark-tree xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:if test="$head-level ge '1'">
...
If I try to include the same code snippet in a form of XSL stylesheet, it is the same—it is injected there properly but it does not add its functionality to the whole stylesheet, it is there still untranslated.
Is there any specific practice or limitation I am not aware of? How to do that properly?
For me, the working solution was not XInclude but xsl:include and calling the template at the proper time:
...
</fo:declarations>
<!-- Bookmarks from the external stylesheet -->
<xsl:call-template name="bookmark-tree"/>
<fo:page-sequence master-reference="title-page">
...
I created the proper stylesheet. The important thing was to set the root element to the current context:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="2.0">
<xsl:template name="bookmark-tree" match=".">
<fo:bookmark-tree>
...
And of course, it was necessary to include the stylesheet into the one where I call the template:
<xsl:include href="common/bookmark-tree.xsl"/>
For now, I consider this question as answered.
I want to copy the namespaces in the elements. The namespace attribute and its value may vary and can occur in any element. But I want to copy the namespace as it is. Also I should not include any attribute as additional to copy the namespace. I am using Saxon 9(he) XSLT processor for transformations
In the below XML file, I am getting the element <ct-ext:case> with the "xmlns:ct-ext" attribute missing. I tried copy-namespaces="yes", yet I am not getting the correct output. I am writing a common XSLT for various DTDs.
Sample XML:
<?xml version="1.0" encoding="UTF-8"?>
<ct:doc identifier="GPPCIA702661235" xsi:schemaLocation="http://test.com/test test.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ct="http://test.com/test" xmlns="http://www.w3.org/1998/Math/MathML" xmlns:ct-ext="http://test.com/test-ext">
<ct:doc-meta identifier="EHIXRW383636159">
<ct:para><ct:inline-math identifier="RCSNDD453018159"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mrow><mi>$</mi><mn>1.65</mn></mrow></math></ct:inline-math></ct:para>
<ct-ext:case identifier="CDVOXU875594216" xmlns:ct-ext="http://test.com/test-ext">
<ct:simple-meta identifier="HNKRFT326435269">
<ct:title identifier="CGSVLX990515344">This is title</ct:title>
</ct:simple-meta>
</ct-ext:case>
</ct:doc-meta>
</ct:doc>
Output Required:
<?xml version="1.0" encoding="UTF-8"?>
<ct:doc identifier="GPPCIA702661235" xsi:schemaLocation="http://test.com/test test.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ct="http://test.com/test" xmlns="http://www.w3.org/1998/Math/MathML" xmlns:ct-ext="http://test.com/test-ext">
<ct:doc-meta identifier="EHIXRW383636159">
<ct:para><ct:inline-math identifier="RCSNDD453018159"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mrow><mi>$</mi><mn>1.65</mn></mrow></math></ct:inline-math></ct:para>
<ct-ext:case identifier="CDVOXU875594216" xmlns:ct-ext="http://test.com/test-ext">
<ct:simple-meta identifier="HNKRFT326435269">
<ct:title identifier="CGSVLX990515344">This is title</ct:title>
</ct:simple-meta>
</ct-ext:case>
</ct:doc-meta>
</ct:doc>
XSLT tried:
<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ct="http://test.com/test" xmlns="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:ct-ext="http://test.com/test-ext">
<xsl:output method="xml" encoding="UTF-8" indent="no"/>
<xsl:template match="#*|node()">
<xsl:copy copy-namespaces="yes">
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Whether you use copy-namespaces or not does not matter (yes is the default anyway), if the input XML has a duplicated namespace declaration on an inner element node then the data model the XSLT processor operates on is not different from the one produced if the inner namespace declaration were not present.
So
<root xmlns:ct-ext="http://test.com/test-ext">
<ct-ext:case xmlns:ct-ext="http://test.com/test-ext">...</ct-ext:case>
</root>
does not differ from
<root xmlns:ct-ext="http://test.com/test-ext">
<ct-ext:case>...</ct-ext:case>
</root>
Consequently when serializing the copied result tree the originally duplicated namespace declaration is lost. I don't think there is a way with XSLT to prevent that.
To elaborate on what Martin said: you are putting requirements on XML tools (like XSLT) that they're not designed to fulfill.
It will help if we use more precise terminology. What you're asking to copy are not namespaces, but rather namespace declarations.
XML tools are designed to be able to produce specified XML elements (and other nodes) in the namespaces that you specify them to be in. This is part of the XML information model.
XML tools are not required to let you specify what namespace prefixes to use, or where to put namespace declarations, so long as the output XML has the right elements and attributes in the right namespaces.
So the requirements you're specifying should not be necessary for any downstream XML consumer. Maybe if you explain why you want namespace declarations to come out in a certain way, we can help you find ways to achieve those purposes, ways that are compatible with how XML namespaces are designed to work.
JBoss ESB 4.11
Hello!
I work with the JBoss ESB 4.11, we are create webservice proxy and we need transform the payload message with xslt transformation. But I can find any functional example to use.
This is a example of the original message
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cim:ESRGERAL xmlns:cim="http://iec.ch/TC57/2007/profile#">
<cim:Terminal>
<cim:mRID>_012345_term</cim:mRID>
<cim:aliasName>term01</cim:aliasName>
<cim:name>term01</cim:name>
and this is the xslt file
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="*">
<ESRGERAL xmlns:cim="http://iec.ch/TC57/2007/profile#">
<xsl:for-each select="//cim:Terminal">
<Terminal>
<mRID>
<xsl:value-of select="cim:mRID"/>
</mRID>
<name>
<xsl:value-of select="cim:aliasName"/>
</name>
</Terminal>
</xsl:for-each>
</cim:ESRGERAL>
</xsl:template>
</xsl:stylesheet>
I need to help to create the correct configuration in jboss-esb.xml, this two files work fine when I use a java implementation, but I can make the same in jboss esb.
If you want to use XSLT for transforming XML-payloads then I believe the XsltAction is what you are looking for:
http://docs.jboss.org/jbossesb/docs/4.11/manuals/html/Programmers_Guide/index.html#OOB-transformers-xsltaction
Not sure that this fully answers your question but in any case, your use case seems very straight forward so I believe JBoss ESB will support it right out of the box without the need for custom code.
One caveat is if you really need to use XSLT 2.0 and not XSLT 1.0 (like in your example), then you will need to do something to make it load your 2.0 XSLT library instead of the standard.
I would seek this your guidance for doubt in XSLT. In my current project there is a requirement to create many XSLT files. In these transformations, there are few common steps performed; for.eg. changing uppercase of an element value from input xml. I'm currently using the below code in an XSLT, so if there are 50 XSLT being created then this code will be duplicated.
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:message>UPPERCASE is <xsl:value-of select="translate($MsgType, $smallcase, $uppercase)" /></xsl:message>
Requesting your advice on how to avoid code duplication. Can I create a common XML file such as utility and declare the variables uppercase and smallcase and shall I call these variables inside the xslt. Similar to other prog. lang like java where I can declare a common function globally and use it in different classes. Basically I would like to know whether it is possible to declare globally and use it in all the xslt.
I would use <include/> to include the XSLT file with all your global variables defined.
See also http://www.w3.org/TR/xslt#element-include
Put all your variables into the file "my_global_variables.xsl":
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="myVariable" select="'xyz'"/>
<!-- more variables to add -->
</xsl:stylesheet>
Your main stylesheet looks like this then, including the "my_global_variables.xsl":
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:include href="my_global_variables.xsl"/>
<xsl:template match="/">
</xsl:template>
</xsl:stylesheet>
There is also the <import> element with which you can import stylesheets. An imported style sheet has lower precedence than the importing style sheet though - so in your case I would use <include>.
Requesting your advice on how to avoid code duplication. Can I create
a common XML file such as utility and declare the variables uppercase
and smallcase and shall I call these variables inside the xslt.
<xsl:import> and <xsl:include> are the two XSLT instructions especially designed for this task.
Global variables (children of an xsl:stylesheet element) in a stylesheet module are accessible in the stylesheet that includes this stylesheet. The rules with importing are a little bit more complicating, but if there are no naming conflicts between global variables from imported stylesheets, they are all accessible from the importing stylesheet.
Finally, I recommend not to use www.w3schools.com -- see why at: http://www.w3fools.com