Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Using the XSLT processor for non-workbench XSLT

Former Member
0 Kudos

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

4 REPLIES 4

Rashid_Javed
Contributor
0 Kudos

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

RJv

0 Kudos

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

0 Kudos

Since my program is practically unreadable here, I have provided a pastebin

[http://pastebin.com/Cj19qtJi]

Former Member
0 Kudos

Problem is solved.

See above test program for the needed functionality.