I have a project where I need to send an email from JBOSS 6. I'm hoping that I can do it from a stylesheet. Is there a way to call the 'sendmail' service in JBOSS 6 from XSL? I'm just not sure if its possible or even how to do it. If its not possible, maybe I can have the stylesheet output some text into a file somewhere for powershell to watch and send mail from it?
EDIT: I have added code
Here is some code that I am trying to make generate a ".txt" file, but it is not being generated. There are no errors that I can see from the transformer.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exslt"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="text" indent="no"/>
<xsl:variable name="emailPID" select="attr[#tag='00100020']"/>
<xsl:variable name="emailPName" select="attr[#tag='00100010']"/>
<!-- overwritten by application with actual values -->
<xsl:param name="calling" select="'SAMPLE_MOD'"/>
<xsl:param name="called" select="'SERVER1'"/>
<xsl:param name="date" select="'20051206'"/>
<xsl:param name="time" select="'115600.000'"/>
<xsl:template match="/dataset">
<exsl:document href="c:\apps\foo.txt">
<xsl:copy-of select="$emailPID"/>
<xsl:copy-of select="$emailPName"/>
</exsl:document>
</xsl:template>
</xsl:stylesheet>
If my stylesheet is using XSLT1 can I use 'TWO' output methods in one file? One doing "method="xml"" for my applications' function and the other doing "method="text"" to generate a text file?
No, with pure XSLT 1.0 it is not possible to produce multiple output files.
You could use an extension function from EXSLT, see Dimitre Novatchev's answer here. Another solution to your problem is to write two separate XSLT stylesheets, one producing "text" output, the other "xml".
Moreover, the method attribut of the xsl:output element is unique and there cannot be both "xml" and "text" in an XSLT 1.0 stylesheet.
If you use XSLT 2.0, however, this functionality is covered by the xsl:result-document element. This element can be used multiple times and also has a method attribute.
Related
This is my code which is working, it seems it uses version 1.0 but I am not sure if some other version can be used also?
Now I need to add just one more element which will have some unique ID sent below the STATUS element, for example CORRELATIONID.
How to add it in most simple way? I read something similar for version 2.0 but I am not sure if this is applicable to my code so please tell me what should I do?
I am using solely XSLT not with C# or anything similar.
Thank you
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:max="http://www.ibm.com/maximo">
<xsl:template match="/">
<max:SyncMXWO Destination="SCCD" Action="urn:processDocument">
<max:MXWOSet>
<max:WORKORDER>
<xsl:apply-templates select="UpdateTaskAssignmentEx/Task" />
</max:WORKORDER>
</max:MXWOSet>
</max:SyncMXWO>
</xsl:template>
<xsl:template match="Task">
<max:WONUM><xsl:value-of select="CallID"/></max:WONUM>
<max:STATUS>COMPLETE</max:STATUS>
</xsl:template>
</xsl:stylesheet>
I think using
<xsl:template match="Task">
<max:WONUM><xsl:value-of select="CallID"/></max:WONUM>
<max:STATUS>COMPLETE</max:STATUS>
<CORRELATIONID><xsl:value-of select="generate-id()"/></CORRELATIONID>
</xsl:template>
should suffice to generate a unique id for each Task element you process in a single run of your XSLT stylesheet.
I have this code so far: - now updated with different code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="xml"/>
<xsl:variable name="emailPID" select="attr[#tag='00100020']"/>
<xsl:variable name="emailPName" select="attr[#tag='00100010']"/>
<!-- overwritten by application with actual values -->
<xsl:param name="calling" select="'SAMPLE_MOD'"/>
<xsl:param name="called" select="'SERVER1'"/>
<xsl:param name="date" select="'20051206'"/>
<xsl:param name="time" select="'115600.000'"/>
<xsl:template match="/dataset">
<exsl:document href="file:///c|/apps/foo.txt">
<xsl:copy-of select="$emailPID"/>
<xsl:copy-of select="$emailPName"/>
</exsl:document>
</xsl:template>
</xsl:stylesheet>
The transformer doesn't throw any errors that I see, but I cannot see the "c:\apps\foo.txt" file I am expecting either. Is there some formatting wrong here or am I leaving something out?
thank you for looking
The processor should throw an error when it sees
extension-element-prefixes="exslt"
because the prefix "exslt" has not been declared. Perhaps you meant "exsl". At present, "exsl" is not declared as an extension namespace, therefore "exsl:document" is a simple literal result element rather than an instruction.
The href attribute of an exsl:document needs to be a valid URI. The XSLT engine is probably confusing the part before the colon (i.e. c) as a URI scheme, not part of the path.
If you are using an absolute address for the filesystem, include the file: URI scheme:
<exsl:document href="file:///c:\apps\foo.txt">
The drive colon ad slashes may cause problems on non-windows platforms so you can instead try:
<exsl:document href="file:///c|/apps/foo.txt">
I have a set of XML files similar to this:
Example Input File:
<a-list>
<a-item key_field="unique1" other="foo"/>
<a-item key_field="unique2" other="foo"/>
...
</a-list>
and I have a transform that will merge these files into a single file of the same structure. It generates the same outer level element (<a-list>) containing all of the <a-item> elements from the files, and discards duplicate entities (entities having the same key_field). I am now faced with several other sets of files, each very similar in its top level structure, that I need to perform almost the same exact kind of merge.
For example, these files might look like this:
<b-list>
<b-item different_key_field="unique93" other="foo"/>
<b-item different_key_field="unique94" other="foo"/>
...
</b-list>
These other files have different data in them, but the transform is generically the same: I need to take multiple input files that have the same structure (a root level containing a list of items, where the items are uniquely identified by a key attribute), and produce an output file that has the top level element containing all of the (unique) items from each of the input files.
Unfortunately, my "merge" transform operates specifically on the named elements in the input files (e.g. it has templates for <a-item> nodes, and it specifically looks for duplicated key_field attributes). It is fairly trivial to copy the transform, search/replace the element names and the key attribute name, but it seems horribly inefficient to duplicate the same code once for each type of input file. The only things that are different are the name of the root element, the name of the item element, and the name of the key attribute. What I want to do (merge) remains the same.
How can I write a transformation that can perform this kind of merge operation without specifying the exact names of the elements/attribute, so that I can invoke the same transform for each type of file? Is there any way to accept the root element name, item element name, and key attribute name as parameters?
As additional constraints, I'm limited to using Xalan, so I believe that means XSL 1.0 only, and it would be best to avoid any extensions.
I thought about transforming an XSL with another XSL, but that seems rather convoluted for such a simple thing.
I've tried searching here and around the internet via Google, but I'm somewhat new to XSL, and all of the words I can think to search in association with XSL or XSLT seem to have specific meanings in the XSL context that make them less useful as search terms (e.g. XSL template, generic XSL, etc.). Some vocab and some good links would be great, an example would be amazing.
Many Thanks,
Russ
Here is a complete solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pDoc1File" select="'b-list-file1.xml'"/>
<xsl:param name="pDoc2File" select="'b-list-file2.xml'"/>
<xsl:param name="pElemName" select="'b-item'"/>
<xsl:param name="pKeyAttrName" select="'different_key_field'"/>
<xsl:variable name="vDoc1" select="document($pDoc1File)"/>
<xsl:variable name="vDoc2" select="document($pDoc2File)"/>
<xsl:template match="/">
<xsl:apply-templates select="$vDoc1/node()"/>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:copy-of select=
"*[name()=$pElemName]
[not(#*[name()=$pKeyAttrName]
=
$vDoc2/*/*[name()=$pElemName]
/#*[name()=$pKeyAttrName])
]"/>
<xsl:copy-of select=
"$vDoc2/*/*[name()=$pElemName]
[not(#*[name()=$pKeyAttrName]
=
$vDoc1/*/*[name()=$pElemName]
/#*[name()=$pKeyAttrName])
]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
File: b-list-file1.xml
<b-list>
<b-item different_key_field="unique93" other="foo"/>
<b-item different_key_field="unique94" other="foo"/> ...
</b-list>
File: b-list-file2.xml
<b-list>
<b-item different_key_field="unique92" other="foo"/>
<b-item different_key_field="unique93" other="foo"/> ...
</b-list>
When this transformation is applied on any XML document (not used / ignored), the wanted, correct result is produced:
<b-list>
<b-item different_key_field="unique94" other="foo"/>
<b-item different_key_field="unique92" other="foo"/>
</b-list>
Explanation:
The filepaths (URLs) to the documents to be processed are provided as global (external to the transformation) parameters.
The name of the elements is provided in a global parameter.
The name of the "key" attribute is provided as a global/external parameter.
Finally, the XPath expressions in the select attributes of the two <xsl:copy-of> instructions, use the values of the parameters for selecting the appropriately-named elements and attributes.
Do note: Every XSLT processor has its own implementation of setting and passing parameters to the transformation. Read this in the Xalan documentation.
Well you can solve your problem with parameters. There is no notion of templated xsl like C++ templates for example, but with parameters you can achieve this effect. For example one of my xslt files looks like this :
<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:space="preserve" version="2.0">
<!--Output type to be used with the xsl:result-document-->
<xsl:output name="html" encoding="utf-8" method="html" indent="yes" doctype- system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>
<!--Global output type-->
<xsl:output encoding="utf-8" method="html" indent="yes" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>
<!--xml output-->
<xsl:output name="xml" encoding="utf-8" method="xml" indent="yes"/>
<xsl:param name="sapFile" as="xs:string" required="yes"/>
<xsl:param name="automaticDate" as="xs:string" required="yes"/>
<xsl:param name="generatePDF" as="xs:string" required="yes"/>
<xsl:param name="fileName" as="xs:string" required="yes"/>
.
.
.
The important element here is xsl:param. You can pass these parameter when you "call" your xsl transform. These parameters in your case would be for example : in one case a-list and in the other case b-list etc. Then you can use these parameters like $param wherever you want in your xslt code so that you can achieve genericity.
I hope that give you some pointers :)
I'm creating an xlst script and was wondering if it is possible to branch some code depending on the output format?
On top of my xlst file I have this:
<xsl:output
version="4.0"
method="html"
indent="no"
encoding="UTF-8"
use-character-maps="spaces"/>
So I suppose there is something out there to inquire some sort of global to do this:
<xsl:if test='global_output is html'>
do this
</xsl:if>
Thank you!
If you want to create variants of a stylesheet for use in different situations, don't put if/then/else code inside the template rules to test the condition at run-time. That way you end up with spaghetti. Create two stylesheet modules to-html.xsl and to-xml.xsl, and have both import a module common.xsl that contains the shared code. The common.xsl module can call back to the importing module when it needs to invoke functionality that varies between the two cases. One of the differences between the two cases is of course the xsl:output declaration itself.
In 1.0 one can use:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output version="4.0"
method="html" indent="no" encoding="UTF-8"/>
<xsl:template match="/*">
<xsl:if test="document('')/*/xsl:output/#method = 'html'">
Output method is HTML
</xsl:if>
<xsl:if test="document('')/*/xsl:output/#method = 'xml'">
Output method is XML
</xsl:if>
</xsl:template>
</xsl:stylesheet>
May be there is a classier way to do it in XSLT 2.0.
There's an XSL that includes another XSL:
<xsl:include href="registered.xsl"/>
That included file has a list of nodes:
<g:registered>
<node1/>
<node2/>
</g:registered>
Documentation says that "the children of the <xsl:stylesheet> element in this document replace the element in the including document", so I would think that, given the include directive has worked, I can select g:registered nodes like if they always belonged to the inluding document:
select="document('')/xsi:schema/g:registered"
That returns an empty nodeset though.
However, this:
select="document('registered.xsl')/xsi:schema/g:registered"
does select what is required, but that, as I suppose, means opening the included file for the second time which doesn't seem nice to me.
So how do I select those includes without opening the file second time?
EDIT
Requested document structure:
Included document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<g:registered-templates>
<SampleTemplate/>
<WrongTemplate/>
</g:registered-templates>
<xsl:include href="Sample Template.xsl" />
<xsl:include href="Wrong Template.xsl" />
</xsl:stylesheet>
Including document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<xsl:output method="text"/>
<xsl:include href="Label Registration.xsl"/>
<!-- How do I refer to just loaded inclusion without directing engine to the file again? -->
<xsl:variable name="template-names" select="document('Label Registration.xsl')/xsl:stylesheet/g:registered-templates"/>
<xsl:template match="Job">
<xsl:for-each select="WorkItem">
<xsl:apply-templates select="$template-names/*[local-name()=current()/#name]">
<xsl:with-param name="context" select="." />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Selecting into your variable template-names queries the transformation source document - not your included stylesheet.
If you want to refer to g:registered-templates you have to point to the file like a second source document.
EDIT
I'm not really sure. but it looks like you want to create an element according to the attribute value.
In that case this post will be interesting for you.
<xsl:for-each select="WorkItem">
<xsl:element name="{Type}" >
<xsl:value-of select="current()/#name"/>
</xsl:element>
</xsl:for-each>
Ok, my understanding was wrong.
The document('') function opens the file anyway, so it has no advantages, performance-wise, over document('registered.xsl'). And since it queries the file, not the now-modified DOM model of current document, the result does not include my includes.
And it is not possible to query DOM model of the transformation template itself, as far as I'm concerned.