I have recently installed saxon9he from sourceforge (4 April 2010) and was hoping to get it working with php.
Your wrapper took a bit of time to get working because my saxon 9 reports itself as saxon 8 and will not accept command line arguments '-s' and '-xsl' .
To get the wrapper working after I got 'Trying to get property of non-object' notices, using the '$xslt2->getErrors()->message' when '$xslt2->transformToXML' failed, I looked at the command line the wrapper was creating.
When I got the saxon9he.jar to work, I used a line like:
I admit I'm guilty of not doing any tests with Saxon9HE, so something like that was expected to eventually occur.
However, Saxon being treated as SAXON8 was not expected. I'm sure I made it to use SAXON9 if the version is not recognized… maybe SAXON returned to the old SAXON8 file naming convention or something… I'll have to check it out.
As for the files opening in the temp dir (which is the reason you need to specify absolute include and document() paths)… I've been told this before, but have no Linux to test it out, and am unable to duplicate it on Windows. I've never understood why this happens… could it be a bug in PHP itself? What XML_XSLT2Processor does is to check the documentURI property of the DOMDocument, and then creates a temporary file (with tempnam()) in that directory with the serialized contents of the DOMDocument… maybe the Linux version of PHP simply never alters the documentURI property?
As I have no Linux, can you please confirm that please? Simply see if
Outputs the expected result (the location, including filename, of the p.xsl file). If it's outputting something inside "/private/var/tmp/", then this is a PHP bug, and you should report it.
You can workaround this bug by not using DOMDocument. Instead, supply the filepath directly to importStylesheet(), like
$xslt2->importStylesheet('p.xsl');
And XML_XSLT2Processor will pass it literally on the command line (almost… it does a realpath()), instead of creating a carbon copy that (as is in this case) may be in another location.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Opps… I'm sorry… I meant MAC, not Linux… but I've heared the same for Linux, and since both use the same kind of paths, this must be something path related.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your reply and the helpful suggestions.
The code you included above did return the full path and file name of the DOMDocument, and using a string with a filename as the argument to importStyleSheet() enabled me to transform using a stylesheet with relative paths for both xsl:include elements and document() functions.
Using the filename causes the command line generated to use the original xsl file and path. When I import it first as a DOMDocument a temporary copy is created and that appears on the generated command line, hence the problem of relative paths.
I'm not sure why saxon9he calls itself 'Saxon 8.0 from Saxonica' when I use it from the command line, or why it only accepts the older form of command line arguments. Perhaps I need to ask them
The work around for relative paths issue certainly works.
Thanks again for a very useful piece of software.
PS. I left a crucial line out of the code I pasted into my initial message:
$xslt2 = new XML_XSLT2Processor('SAXON9','saxon9he.jar','JAVA-CLI');
Mea cupla!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
What exactly does the documentURI look like? Exactly like the filepath, i.e.
/Users/rydal/p.xsl
or is it more like
file:////Users/rydal/p.xsl
I'm starting to think it may be the literal file path, and not a file URI… it would explain why it's failing… the url2filepath() function is thinking this is an URL relative to the document root, and after the realpath() is later done, the file is created in the temporary folder because the bool(false) folder doesn't exist.
If that's the case, this should be fixed in the new version I'm preparing… I have a completely rewritten url2filepath() function that handles this (and other edge) case(s) much better… at least in theory.
BTW, I've also noticed the actual change you've made to the command line, and now I remembered (sorry I didn't recalled it last time) why it is done like that - what you've done is you've eliminated the custom error handler. The handler was implemented by a custom jar, which acts as a "proxy" to SAXON - it simply passes literally what it receives on the command line, right after it first sets the error handler. That error handler deliver errors in a form which is easy for PHP to process, and it therefore gives proper error messages on the PHP end. If there are any errors or warnings from SAXON, they're currently hidden from you… except if you're willing to inspect your raw error log.
To preserve the error handler, while still using the -jar switch (I didn't get why doesn't the plain class call work for your… an old JRE maybe?), try replacing
Note to self: SERIOUSLY consider installing some kind of a Linux (Ubuntu maybe?) as a VM… the Windows part is already stable enough (I even thought about removing the "beta" tag from the project), but the same can't be said about other platforms.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You are right in your suspicions that DOMDocument->documentURI returns not a URI but a filepath.
I did indeed get a string like '/Users/rydal/p.xsl' from the code you suggested:
I think my JRE is up to date (it came with Leopard) - the reason why I put the saxon jar in the directory with the xml and xsl was to make sure I wasn't accidently using an older version (which would have explained it reporting itself as Saxon 8).
I tried the change to the command line you suggested. It produced something like:
Oh, everything you've said has been tremendously useful indeed.
I have released a new version - v0.5.3 that should address all of the issues you've had. Give it a whirl ^_^ .
Keep in mind you should use "SAXON9he" or just "SAXON" as the processor, but not just "SAXON9".
The main problem with the "… property of non-object" error was in the custom JAR itself. I was reconstructing the configuration from scratch, but it appears SAXON9he has changed the way it constructs it, which is why it was throwing exceptions that resulted in the PHP error.
Also, the url2filepath() function is still the same, but with a minor tweak specifically for your case - if the path starts with "/", it should be considered a UNIX absolute filepath (if "/" exists), and no further processing on it will be done. This is NOT the rewritten function I was talking about… I'm not at all confident yet about the new functions' stability, because coverage tests show that while it works for the things I throw at it, it goes into unexpected directions, which for me is worrying.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have just given the new version (0.5.3) a whirl and it works fine on my Mac. It copes with relative paths for documents and includes.
What it does not do, which would be very useful, is return the detailed error information I can get if I run the command in Terminal (just the 'Trying to get property of non-object' notice).
I don't need this for the website version, of course, but that is just a tip if you are wondering what sort of error reporting you get on the Mac.
Thanks again for to the very useful software.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
What it does not do, which would be very useful, is return the detailed error information I can get if I run the command in Terminal (just the 'Trying to get property of non-object' notice).
I'm not sure I follow… do you mean errors from SAXON itself? You can get those with the getErrors() method…
Speaking of which, in your initial code sample, you're using it wrong.
echo $xslt2->getErrors()->message;
Would probably result in a "Trying to get property of non-object" error because getErrors() returns an array of errors, not a single error. If you want to view the last error, you can instead use
echo $xslt2->getErrors(-1)->message;
And if you want to view all error messages, you can loop over the array, and echo it all, i.e.
foreach($xslt2->getErrors() as $error) {
echo $error->message, "\n\n";
}
BTW, as a side note, you should probably report the file path problem with DOMDocument::documentURI to the PHP developers. While PHP doesn't violate the DOM spec per se (since the spec has a very loose definition of URIs in the DOM), having a little consistency between platforms wouildn't hurt, right? For the sake of this consistency, those UNIX filepaths should instead be file URIs… I would report this myself, but since you're the one with the OS having the undesired behaviour, you should report it in case the PHP developers need some additional information.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have recently installed saxon9he from sourceforge (4 April 2010) and was hoping to get it working with php.
Your wrapper took a bit of time to get working because my saxon 9 reports itself as saxon 8 and will not accept command line arguments '-s' and '-xsl' .
To get the wrapper working after I got 'Trying to get property of non-object' notices, using the '$xslt2->getErrors()->message' when '$xslt2->transformToXML' failed, I looked at the command line the wrapper was creating.
When I got the saxon9he.jar to work, I used a line like:
java -jar saxon9he.jar -o p.html p.xml p.xsl Lang=en
so I modified the line in XSLT2Processor.php (line 826)
$this->command = ($isJAVA ? 'java -cp ' : null) . escapeshellarg(($isJAVA ? dirname(__FILE__) . DIRECTORY_SEPARATOR . 'XSLT2Processor.jar' . PATH_SEPARATOR : null) . $this->processorPath) . ($isJAVA ? ' xslt2processor.saxon' : null) . ' -o' . ($this->processorVersion === 9 ? ':' : ' ') . $inputs . $commandOptions . ($this->processorVersion === 9 ? ' -s:' : ' ') . $inputs . ($this->stylesheet !== XML_XSLT2PROCESSOR_PI ? ($this->processorVersion === 9 ? ' -xsl:' : ' ') . $inputs : null) . ' ' . $params;
to read:
$this->command = ($isJAVA ? 'java -cp ' : null) . escapeshellarg(($isJAVA ? dirname(__FILE__) . DIRECTORY_SEPARATOR . 'XSLT2Processor.jar' . PATH_SEPARATOR : null) . $this->processorPath) . ($isJAVA ? ' -jar ' . $this->processorPath : null) . ' -o' . ($this->processorVersion === 9 ? ':' : ' ') . $inputs . $commandOptions . ' ' . $inputs . ($this->stylesheet !== XML_XSLT2PROCESSOR_PI ? ' ' . $inputs : null) . ' ' . $params;
to produce command lines like:
java -cp '/usr/local/PEAR/XML/XSLT2Processor.jar:/Users/rydal/saxon9he.jar' -jar /Users/rydal/saxon9he.jar -o:/private/var/tmp/RESULT_TEMPuUhU18 /Users/rydal/p.xml /private/var/tmp/XSL_TEMPXAsdiN
I know it is a bit of a hack, but now when I call $xslt2->transformToXML it works!
Thanks!
I am using PHP 5 on a Mac PowerBook G4 running Leopard.
My source is:
<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>XSLT2 Processor Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>XSLT2 Processor Test</h1>
<?php
include "XML/XSLT2Processor.php";
XML_XSLT2Processor::clearErrors ();
$xsldoc = new DOMDocument();
$xsldoc->load('p.xsl');
$xslt2->importStyleSheet($xsldoc);
if ($output = $xslt2->transformToXML('p.xml')) {
echo '<p>Success:</p><pre>';
echo $output;
echo '</pre><p>Used command:</p><p>';
echo $xslt2->command;
echo '</p>';
}else {
echo '<p>Transformation Failure:</p><pre>';
echo $output;
echo '</pre><p>Used command:</p><p>';
echo $xslt2->command;
echo '</p><p>Got these error(s)</p><p>';
echo $xslt2->getErrors()->message;
echo '</p>';
}
?>
(The p.xml and p.xsl files I got from http://en.wikipedia.org/wiki/Xslt )
Apart from the need to use absolute paths for the xsl:includes and in the document() function it works great!
Thank you, boen_robot !!
Thanks for reporting this.
I admit I'm guilty of not doing any tests with Saxon9HE, so something like that was expected to eventually occur.
However, Saxon being treated as SAXON8 was not expected. I'm sure I made it to use SAXON9 if the version is not recognized… maybe SAXON returned to the old SAXON8 file naming convention or something… I'll have to check it out.
As for the files opening in the temp dir (which is the reason you need to specify absolute include and document() paths)… I've been told this before, but have no Linux to test it out, and am unable to duplicate it on Windows. I've never understood why this happens… could it be a bug in PHP itself? What XML_XSLT2Processor does is to check the documentURI property of the DOMDocument, and then creates a temporary file (with tempnam()) in that directory with the serialized contents of the DOMDocument… maybe the Linux version of PHP simply never alters the documentURI property?
As I have no Linux, can you please confirm that please? Simply see if
Outputs the expected result (the location, including filename, of the p.xsl file). If it's outputting something inside "/private/var/tmp/", then this is a PHP bug, and you should report it.
You can workaround this bug by not using DOMDocument. Instead, supply the filepath directly to importStylesheet(), like
And XML_XSLT2Processor will pass it literally on the command line (almost… it does a realpath()), instead of creating a carbon copy that (as is in this case) may be in another location.
Opps… I'm sorry… I meant MAC, not Linux… but I've heared the same for Linux, and since both use the same kind of paths, this must be something path related.
Thank you for your reply and the helpful suggestions.
The code you included above did return the full path and file name of the DOMDocument, and using a string with a filename as the argument to importStyleSheet() enabled me to transform using a stylesheet with relative paths for both xsl:include elements and document() functions.
Using the filename causes the command line generated to use the original xsl file and path. When I import it first as a DOMDocument a temporary copy is created and that appears on the generated command line, hence the problem of relative paths.
I'm not sure why saxon9he calls itself 'Saxon 8.0 from Saxonica' when I use it from the command line, or why it only accepts the older form of command line arguments. Perhaps I need to ask them
The work around for relative paths issue certainly works.
Thanks again for a very useful piece of software.
PS. I left a crucial line out of the code I pasted into my initial message:
$xslt2 = new XML_XSLT2Processor('SAXON9','saxon9he.jar','JAVA-CLI');
Mea cupla!
What exactly does the documentURI look like? Exactly like the filepath, i.e.
or is it more like
I'm starting to think it may be the literal file path, and not a file URI… it would explain why it's failing… the url2filepath() function is thinking this is an URL relative to the document root, and after the realpath() is later done, the file is created in the temporary folder because the bool(false) folder doesn't exist.
If that's the case, this should be fixed in the new version I'm preparing… I have a completely rewritten url2filepath() function that handles this (and other edge) case(s) much better… at least in theory.
BTW, I've also noticed the actual change you've made to the command line, and now I remembered (sorry I didn't recalled it last time) why it is done like that - what you've done is you've eliminated the custom error handler. The handler was implemented by a custom jar, which acts as a "proxy" to SAXON - it simply passes literally what it receives on the command line, right after it first sets the error handler. That error handler deliver errors in a form which is easy for PHP to process, and it therefore gives proper error messages on the PHP end. If there are any errors or warnings from SAXON, they're currently hidden from you… except if you're willing to inspect your raw error log.
To preserve the error handler, while still using the -jar switch (I didn't get why doesn't the plain class call work for your… an old JRE maybe?), try replacing
with
Note to self: SERIOUSLY consider installing some kind of a Linux (Ubuntu maybe?) as a VM… the Windows part is already stable enough (I even thought about removing the "beta" tag from the project), but the same can't be said about other platforms.
You are right in your suspicions that DOMDocument->documentURI returns not a URI but a filepath.
I did indeed get a string like '/Users/rydal/p.xsl' from the code you suggested:
So your new version should fix this.
I think my JRE is up to date (it came with Leopard) - the reason why I put the saxon jar in the directory with the xml and xsl was to make sure I wasn't accidently using an older version (which would have explained it reporting itself as Saxon 8).
I tried the change to the command line you suggested. It produced something like:
java -cp '/usr/local/PEAR/XML/XSLT2Processor.jar:/Users/rydal/saxon9he.jar' -jar XSLT2Processor.jar -o:/private/var/tmp/RESULT_TEMPVgse3w /Users/rydal/p.xml /Users/rydal/p.xsl
Unfortunately, it caused the 'Trying to get property of non-object' notice again, so I have reverted to what worked:
java -cp '/usr/local/PEAR/XML/XSLT2Processor.jar:/Users/rydal/saxon9he.jar' -jar /Users/rydal/saxon9he.jar -o:/private/var/tmp/RESULT_TEMPDTgD1Y /Users/rydal/p.xml /Users/rydal/p.xsl
(I'm not quite sure what is causing this. Unfortunately, my php, when reporting errors does not tell me the correct line numbers!)
I hope all this is of use to you.
Thanks again
Oh, everything you've said has been tremendously useful indeed.
I have released a new version - v0.5.3 that should address all of the issues you've had. Give it a whirl ^_^ .
Keep in mind you should use "SAXON9he" or just "SAXON" as the processor, but not just "SAXON9".
The main problem with the "… property of non-object" error was in the custom JAR itself. I was reconstructing the configuration from scratch, but it appears SAXON9he has changed the way it constructs it, which is why it was throwing exceptions that resulted in the PHP error.
Also, the url2filepath() function is still the same, but with a minor tweak specifically for your case - if the path starts with "/", it should be considered a UNIX absolute filepath (if "/" exists), and no further processing on it will be done. This is NOT the rewritten function I was talking about… I'm not at all confident yet about the new functions' stability, because coverage tests show that while it works for the things I throw at it, it goes into unexpected directions, which for me is worrying.
I'm glad my comments have been useful.
I have just given the new version (0.5.3) a whirl and it works fine on my Mac. It copes with relative paths for documents and includes.
What it does not do, which would be very useful, is return the detailed error information I can get if I run the command in Terminal (just the 'Trying to get property of non-object' notice).
I don't need this for the website version, of course, but that is just a tip if you are wondering what sort of error reporting you get on the Mac.
Thanks again for to the very useful software.
I'm not sure I follow… do you mean errors from SAXON itself? You can get those with the getErrors() method…
Speaking of which, in your initial code sample, you're using it wrong.
Would probably result in a "Trying to get property of non-object" error because getErrors() returns an array of errors, not a single error. If you want to view the last error, you can instead use
And if you want to view all error messages, you can loop over the array, and echo it all, i.e.
BTW, as a side note, you should probably report the file path problem with DOMDocument::documentURI to the PHP developers. While PHP doesn't violate the DOM spec per se (since the spec has a very loose definition of URIs in the DOM), having a little consistency between platforms wouildn't hurt, right? For the sake of this consistency, those UNIX filepaths should instead be file URIs… I would report this myself, but since you're the one with the OS having the undesired behaviour, you should report it in case the PHP developers need some additional information.