How to implement saxon OutputURIResolver in Java? - java

I am new to Java. I have a similar scenario as [Catch output stream of xsl result-document but I am not understanding what to pass as href and base parameter..
My XSLT (result-document) as follows:
<xsl:template match="/" mode="create-text-file">
<xsl:param name="book-name" tunnel="yes"/>
<xsl:result-document href="{$book-name}.xml"
doctype-public=" test"
doctype-system="test.dtd">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:template>
Another:
<xsl:result-document href="{$book-name}.opf"
doctype-public=""
doctype-system=""
indent="yes">
<xsl:apply-templates mode="#current"/>
</xsl:result-document>
Parameter book-name is getting as :
<xsl:template match="document-node()">
<xsl:variable name="book-name" select="tps:get-file-name(document-uri(/))"/>
Can you please explain me with this result-documents?
Thanks in advance.

OutputURIResolver is a callback: that means you supply the implementation of the resolve() method, and Saxon calls your implementation. So you don't need to worry about what to pass as the base and href arguments, because you don't call the method, Saxon does. It will typically supply the href argument as the (expanded) value of the href attribute of your call to xsl:result-document, and the base value will be the "base output URI", which defaults to the file nominated as the principal output of the transformation (-o option on the command line).

Related

Define XSL variable without type changing

I have a variable in my XSL file. Java returned java.util.List into this variable
<xsl:variable name="testVariable" select="java:getJavaList()"/>
After that this vairable is used in Java by method that takes java.util.List as parameter
<xsl:variable name="anotherVariable">
<xsl:value-of select="java:useTestVariable($testVariable)"/>
</xsl:variable>
Now requirements were changed to set testVariable value depending on particular condition. I tried this approach
<xsl:variable name="testVariable">
<xsl:choose>
<xsl:when test="contains($oneMoreVariable, '%')">
<xsl:value-of select="java:getValue('%')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="java:getDefaulValue()" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
The problem is that if I define variable in this way, it contains not List, but tree fragment. And I get an exception
For extension function, could not find method
MyClassName.useTestVariable([ExpressionContext,] #RTREEFRAG)
Can somebody please advice what is the correct way to define variable value basing on some condition so, that variable's type would not be changed with tree fragment?
I don't think there's any way to do this in XSLT 1.0 as by definition any xsl:variable with content rather than a select must be a result tree fragment. But since you're able to make calls into Java you can put the conditional logic into a Java function, then call that from the variable's select.
Have you verified the resuts of java:getValue('%') and java:getDefaulValue() , if these results are coming out be what you expect and still it is a fragement refer this link https://blogs.oracle.com/rammenon/entry/result_tree_fragments_and_node

markup specific strings in Xml

I like to markup some strings in an xml document.
For example, I have:
<p> I like to go to Florida </p>
I need to tag the string "go" and have the output as:
<p> I like to <something>go</something> to Florida</p>
What is the best way to do this? I am using Java. I need to treat the XML file as XML not as text. I found some solutions that treat an xml file as a text file and use string.replace but I do not think those are good solutions.
Any suggestion is much appreciated.
Thank you,
Try an XSLT 2.0 transformation like this:
<xsl:template match="#*|*">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:analyze-string regex="go">
<xsl:matching-substring>
<something><xsl:value-of select="."/></something>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
You can of course extend the regular expression, e.g. regex="go|come|walk|run"; if you only want to match whole words, you might want to use tokenize() to split it into words and process each word separately.

Check xml tags for certain values and transform - Best practice

I want to do the following :
At this moment we receive some xml-files where some xml-tags are filled wrongly.
To help our partner, we want to catch these false values by using a "Pass-through" folder where all the xml-files are placed before importing in our application.
This folder would be read every X minutes and for every file there will need to be done some checks, like : The length of the value within a tag, the value of the tag, etc.
Because this is only a temporary solution, we don't want to implement it in our application.
I was thinking of 2 possible set-ups :
Using java and calling an XSLT-file to transform every file and put it in another folder
Using only java to check the xml-file and do the transformation.
Both of the cases would be called by a .bat that runs every X minutes.
Now my questions :
What do you think that would be the best solution? a.k.a. the quickest, the most secure, etc. (maybe something other than suggested?)
Could you also provide me some examples of the way to do something like this?
I'm not like other persons who ask strictly for the codes. If you can give me something similar, I can make it on my own.
At the time of this writing, I'm already looking for solutions on other websites, but because it is urgent, it's also helpfull to ask the community.
Thank you for your answer,
Kind regards,
Maarten
EDIT : Both answers helped me a lot. Thank you guys.
http://www.ibm.com/developerworks/xml/library/x-javaxmlvalidapi/index.html
or
http://www.java-tips.org/java-se-tips/javax.xml.validation/how-to-create-xml-validator-from-xml-s.html
or
http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/validation/package-summary.html
If you want to run your XSLT, using a .bat script, on every XML file in a given folder (your first option in the OP) I can think of 3 ways:
A. Basically do a "for" loop to process each individual file via the command line. (Eww.)
B. Use collection() to point to an input folder and use xsl:result-document to create the output files in a new folder.
Here's an example XSLT 2.0 (tested with Saxon 9):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pInputDir" select="'input'"/>
<xsl:param name="pOutputDir" select="'output'"/>
<xsl:variable name="vCollection" select="collection(concat($pInputDir,'/?*.xml'))"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="$vCollection">
<xsl:variable name="vOutFile" select="tokenize(document-uri(document(.)),'/')[last()]"/>
<xsl:result-document href="{concat($pOutputDir,'/',$vOutFile)}">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Notes:
This stylesheet is just doing an identity transform. It's passing the XML through unchanged. You would need to override the identity template by adding new templates to do your checks/changes.
Also notice that there are 2 parameters for the input and output folder names.
You may run into memory issues using collection() because it loads all of the XML files in the folder into memory. If this is an issue, see below...
C. Have your XSLT process a list of all the files in the directory. Use a combination of document() and the Saxon extension function saxon:discard-document() to load and discard the documents.
Here's an example I used a while back for testing.
XML file listing (input to the XSLT):
<files>
<file>file:///C:/input_xml/file1.xml</file>
<file>file:///C:/input_xml/file2.xml</file>
<file>file:///C:/input_xml/file3.xml</file>
<file>file:///C:/input_xml/file4.xml</file>
<file>file:///C:/input_xml/file5.xml</file>
<file>file:///C:/input_xml/file6.xml</file>
<file>file:///C:/input_xml/file7.xml</file>
<file>file:///C:/input_xml/file8.xml</file>
<file>file:///C:/input_xml/file9.xml</file>
<file>file:///C:/input_xml/file10.xml</file>
</files>
XSLT 2.0 (tested with Saxon 9):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pOutputDir" select="'output'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="files">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="file">
<xsl:variable name="vOutFile" select="tokenize(document-uri(document(.)),'/')[last()]"/>
<xsl:result-document href="{concat($pOutputDir,$vOutFile)}">
<xsl:apply-templates select="document(.)/saxon:discard-document(.)" xmlns:saxon="http://saxon.sf.net/"/>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
Notes:
Again, this stylesheet is just doing an identity transform. It's passing the XML through unchanged. You would need to override the identity template by adding new templates to do your checks/changes.
Also notice that there is only a parameter for the output folder name.

How to match and process unknown XML elements in XSLT 1.0?

I have a simply XSLT 1.0 stylesheet, that turns XML documents in XHTML. I really want to be able to "include" the content of an XML file in another when needed. AFAIK it is simply not possible in XSLT 1.0, so I decided to move my processing to a simple Java app that would pre-process the XML, executing the "includes" recursively, and passing it to the default JDK XSLT processor. I have a XML schema that my documents must conform to.
The most used element is called "text", and can have an "id" and/or a "class" attribute, which gets used for XHTML styling with CSS. This element gets turned into "p", "div", or "span" depending on the context.
What I would like to add, is the ability to define "unknown" elements in my input files, and have them transformed in a "text" element for further processing. If the "unknown" element's name start with a capital letter, then it becomes a "text", with "id" set to original name. Otherwise a "text" with "class" set to original name. Everything else in the unknown element should be kept as-is, and then it should be processed by XSLT as if it was originally in the input file. In other words, I would like to transform all unknown elements to for a valid XML document, and then process it with my stylesheet.
Can this be done in XSLT, possibly in a pre-processing "stylesheet", or should I do that as pre-processing in Java? Performance here is not important. I would prefer a XSLT solution, but not if it's much more complicated then doing it in Java.
Well, since no one answered, I just tried it. While is is easier to do it in Java, it has one major drawback: since the code need to know the valid elements so that it recognize the unknown ones, you end up having to hardcode that in your code and have to recompile it if the XSLT template changes.
So, I tried in XSLT and it also works. Let's say you have:
<xsl:template match="text">
*processing*
<xsl:call-template name="id_and_class"/>
*processing*
</xsl:template>
where the template named id_and_class copies your id and classes attribute in the generated element, and you want unknown elements to be mapped to "text" elements, then you can do this:
<xsl:template match="text">
<xsl:call-template name="text_processing"/>
</xsl:template>
<xsl:template name="text_processing">
*processing*
<xsl:call-template name="text_id_and_class"/>
*processing*
</xsl:template>
...
<xsl:template name="text_id_and_class">
<xsl:choose>
<!-- If name() is not "text", then we have an unknown element. -->
<xsl:when test="name()!='text'">
<!-- Processing of ID and class omitted ... -->
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="id_and_class"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
...
<!-- MUST BE LAST : Process unknown elements like a "text" element. -->
<xsl:template match="*">
<xsl:call-template name="text_processing"/>
</xsl:template>
If yon process the content of one specific element with a named template, then you can check in that template if the name matches, and use that for your special processing. Then you just have to put a <xsl:template match="*"> at the end of your stylesheet and call the named template from there.

Formatted HTML as output from method invocation from MX4J HTTP page

I have a huge set of data and want to display the data with some formatting.
This is what the method basically looks like:
#ManagedOperation(description = "return html")
#ManagedOperationParameters({#ManagedOperationParameter(name = "someVal", description = "text")})
public String returnAsHtml(String someVal)
{
return "some formatted xml";
}
Looks like XSLTProcessor can be configured to use a XSLT template. However I could not find any examples on the internet using XSLT for html transformation in the context of MX4J. Could any one provide a sample XSLT template?
In case anyone comes back to this question, two things come to mind:
1) MX4J has several default implementations of HttpCommandProcessorAdaptor. These operations are mapped from the path. For JMX operations (aka ManagedOperation in Spring parlance), MX4J uses URLs like /invoke?operation=returnAsHtml
This will be passed to the InvokeOperationCommandProcessor to create an XML document with the result being just the toString() of whatever you returned, in an attribute called 'return'. It also passes back the return type in an attribute called 'returnclass'. You can see all this if you just add &template=identity to the invoke URL.
I mention all this because one option is to implement your own 'invoke.xsl'. The one in MX4J just calls the renderobject template:
Lo and behold, you find this in mbean_attributes.xsl, with a comment showing you exactly what you need to do:
<xsl:template name="renderobject">
<xsl:param name="objectclass"/>
<xsl:param name="objectvalue"/>
<xsl:choose>
<xsl:when test="$objectclass='javax.management.ObjectName'">
<xsl:variable name="name_encoded">
<xsl:call-template name="uri-encode">
<xsl:with-param name="uri">
<xsl:value-of select="$objectvalue"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<a href="/mbean?objectname={$name_encoded}">
<xsl:value-of select="$objectvalue"/>
</a>
</xsl:when>
<xsl:otherwise>
<!-- Use the following line when the result of an invocation
returns e.g. HTML or XML data
<xsl:value-of select="$objectvalue" disable-output-escaping="true" />
-->
<xsl:value-of select="$objectvalue"/>
</xsl:otherwise>
</xsl:choose>
Setting 'disable-output-escaping' to true will do the trick
2) Another option is to write your own HttpCommandProcessorAdaptor, and set it on the HttpAdapter. This could either replace the 'invoke' processor, or you could have an entirely new one.
Hope that helps
One way I figured out is to use java script in the XSL template to extract and parse the string. Make sure you test for the browser (IE vs Non IE) and use proper parser.

Categories