2008 Jul 03 4:43 PM
Hi there,
is it possible to use the built-in XSLT processor for arbitrary XSLT transformations which aren't checked in in the ABAP workbench but instead given as a runtime object (string or iXML)?
Instead of the built-in command CALL TRANSFORMATION which according to the doc is restricted to workbench transformations, I am looking for an option like this:
data: lo_transformation type ref to if_ixml_document,
lo_source type ref to if_ixml_document,
lo_target type ref to if_ixml_focument.
...
* I get lo_transformation and lo_source from somewhere out there
...
try.
lo_target ?= cl_some_fine_class_which_i_am_looking_for=>transform(
io_source = lo_source
io_transformation = lo_transformation ).
...
catch cx_xslt_runtime_error.
...
endtry.
Does anybody know such a feature?
For a background about this problem - in German language - see my blog
http://ruediger-plantiko.blogspot.com/2007/08/xslt-in-bsp-anwendungen-und-in-abap.html
Thanks and Regards,
Rüdiger
2008 Jul 03 6:28 PM
Well i haven't tried this personally but have a look at package SXSLT_APP OR SXSLT in SE80.
These contain some interesting classes !
In fact class CL_XSLT_PROCESSOR might be the one you are looking for
Edited by: Rashid Javed on Jul 3, 2008 8:28 PM
2008 Jul 04 9:21 AM
Dear Rashid,
thanks - this is the answer! I wonder why I didn't find this class one year ago. A little test prog shows that it works fine and even performant (about 0.5 millisec for creating the new dynamic XSLT program with the method set_source_stream( ) ). For usage in web apps, it would be nice to know whether the temporary program remains available in the application servers' buffer after end of process. I can't check this, since this is performed on the C/C++ level, and SE30 doesn't track the method set_source_stream() itself (it could show a decrease of runtime after the first call).
Here comes a little self-contained ABAP program to test the functionality. It works well on our system with SAPKB70012.
Thanks and regards,
Rüdiger
* --- Test usage of a dynamically given non-workbench XSLT program
report zz_test_cl_xslt_processor.
data:
* iXML master
go_xml type ref to if_ixml,
* iXML stream factory
go_sf type ref to if_ixml_stream_factory.
load-of-program.
go_xml = cl_ixml=>create( ).
go_sf = go_xml->create_stream_factory( ).
start-of-selection.
perform start.
* --- Start
form start.
data: lo_source type ref to if_ixml_document,
lo_result type ref to if_ixml_document,
lo_processor type ref to cl_xslt_processor,
lv_p type progname,
lo_ex type ref to cx_xslt_exception.
perform get_source changing lo_source.
create object lo_processor.
try.
* Set source
lo_processor->set_source_node( lo_source ).
* Set result
lo_result = go_xml->create_document( ).
lo_processor->set_result_document( lo_result ).
* This could be time-critical, the creation of a dynamical XSLT prog?
perform set_transformation using lo_processor
changing lv_p.
* call xslt-proc
lo_processor->run( lv_p ).
* Display result
call function 'SDIXML_DOM_TO_SCREEN'
exporting
document = lo_result
title = 'Result of Transformation'
exceptions
no_document = 1
others = 2.
catch cx_xslt_exception into lo_ex.
sy-msgli = lo_ex->get_text( ).
message sy-msgli type 'I'.
endtry.
endform. "start
* --- Set XSLT transformation from stream
form set_transformation using io_processor type ref to cl_xslt_processor
changing cv_p type progname.
data: lo_trans type ref to if_ixml_istream.
* sv_p contains temp. name of XSLT program after first call
statics: sv_p type string.
if sv_p is initial.
* It seems that the name can be buffered on appserver level?
import progname to sv_p
from shared buffer indx(zx) id 'ZZ_TEST_XSLT_PROC'.
if sv_p is initial.
sv_p = 'X'.
endif.
endif.
* Provide the stream containing the XSLT document (as a stream)
perform get_transformation changing lo_trans.
* Set transformation
io_processor->set_source_stream( exporting stream = lo_trans
changing p = sv_p ).
* Buffer progname on server - seems to work
export progname from sv_p
to shared buffer indx(zx) id 'ZZ_TEST_XSLT_PROC'.
* string -> c move necessary, since xslt-proc-interface doesn't use
* the generic type csequence for program name
cv_p = sv_p.
endform. "set_transformation
* --- Parse a source given as string into an if_ixml_document
form get_source changing co_src type ref to if_ixml_document.
data: lv_s type string,
lo_stream type ref to if_ixml_istream,
lo_parser type ref to if_ixml_parser.
concatenate
`<?xml version="1.0" encoding="iso-8859-1"?>`
`<countings filiale="2412" invnu="TIEFKUEHL SEPT.07">`
`<count recNum="1" gid="1" ean="59111828843" menge="1"`
`preis="0" recNumFrom="1"></count>`
`</countings>`
into lv_s.
* Eingabestream erzeugen und in if_ixml_document abbilden
lo_stream = go_sf->create_istream_string( lv_s ).
co_src = go_xml->create_document( ).
lo_parser = go_xml->create_parser( document = co_src
istream = lo_stream
stream_factory = go_sf ).
lo_parser->parse( ).
endform. "get_source
* --- Put the transformation given as string into an if_ixml_istrean
form get_transformation changing co_trans type ref to if_ixml_istream.
data: lv_s type string.
concatenate
`<?xml version="1.0" encoding="iso-8859-1"?>`
`<xsl:transform version="1.0"`
` xmlns:xsl="http://www.w3.org/1999/XSL/Transform"`
` xmlns:asx="http://www.sap.com/abapxml">`
`<xsl:strip-space elements="*"></xsl:strip-space>`
`<xsl:template match="countings">`
` <asx:abap>`
` <asx:values>`
` <SELOPT>`
` <WERKS><xsl:value-of select="@filiale"></xsl:value-of></WERKS>`
` <INVNU><xsl:value-of select="@invnu"></xsl:value-of></INVNU>`
` </SELOPT>`
` <COUNTINGS>`
` <xsl:for-each select="count">`
` <ZSRS_ZWSTI_LINE>`
` <MATNR></MATNR>`
` <EAN11><xsl:value-of select="@ean"></xsl:value-of></EAN11>`
` <MAKTX></MAKTX>`
` <MENGE><xsl:value-of select="@menge"></xsl:value-of></MENGE>`
` <MEINH></MEINH>`
` <UNAME></UNAME>`
` <EXVKW></EXVKW>`
` <WAERS></WAERS>`
` <FF></FF>`
` <GID><xsl:value-of select="@gid"></xsl:value-of></GID>`
` <RECNUM><xsl:value-of select="@recNum"></xsl:value-of></RECNUM>`
` <RECNUM_FROM><xsl:value-of select="@recNumFrom"></xsl:value-of></RECNUM_FROM>`
` <REF_RECNUM><xsl:value-of select="@refRecNum"></xsl:value-of></REF_RECNUM>`
` </ZSRS_ZWSTI_LINE>`
` </xsl:for-each>`
` </COUNTINGS>`
` </asx:values>`
` </asx:abap>`
`</xsl:template>`
`</xsl:transform>`
into lv_s.
co_trans = go_sf->create_istream_string( lv_s ).
endform. "get_transformation
Edited by: Rüdiger Plantiko on Jul 4, 2008 10:25 AM
2011 Oct 04 4:01 PM
Since my program is practically unreadable here, I have provided a pastebin
[http://pastebin.com/Cj19qtJi]
2008 Jul 04 9:23 AM
Problem is solved.
See above test program for the needed functionality.