Introduction

The following code snippet shows how to validate an XML document present as string in ABAP. Unfortunately there is no possibility to get the whole task done in pure ABAP if XML-schema should be used (validation via DTD is possible). Thus, the following code will only work on MS Windows OS having the Microsoft XML Core Services (MSXML) library installed on the client system. The approach is as follows:

  1. A MS JScript script is downloaded onto the local client.
  2. The XML-schema file is downloaded onto the local client.
  3. The script (1) is executed. Errors during validation are stored into a log file.
  4. The error log file is processed in order to check if the validation was successful.

Code Snippet(s)

DATA:
      lv_xml    TYPE STRING,    "XML document to validate against schema
      lv_valid  TYPE ABAP_BOOL. "Indicator if the given XML is valid

*   Validation only supported for MS-Win OS XP and above.
*   Check the platform.
    DATA: lv_platform TYPE i.

    cl_gui_frontend_services=>get_platform(
      RECEIVING
        platform             = lv_platform    " Gets platform
      EXCEPTIONS
        error_no_gui         = 1
        cntl_error           = 2
        not_supported_by_gui = 3
        OTHERS               = 4
    ).
    IF sy-subrc <> 0 OR lv_platform NE 14.
      RAISE validation_not_possible.
    ENDIF.

*   Build the validation mediation script which is executed on
*   client side.
    DATA:
      lv_validation_script          TYPE string,
      lv_validation_script_filename TYPE string VALUE 'XMLValidation.js',
      lt_string_tab                 TYPE STANDARD TABLE OF string,
      lt_validation_script_tmp      TYPE STANDARD TABLE OF string,
      lv_temp_dir_path              TYPE string,
      lv_filename_separator         TYPE c,
       lv_schema                     TYPE string, "The actual XML-schema
      lv_schema_file_path           TYPE string,
      lv_schema_filename            TYPE string VALUE '.xsd',
      lv_target_namespace           TYPE string VALUE '',
      lv_xml_filename               TYPE string VALUE 'xmlToValidate.xml',
      lv_error_log_file_name        TYPE string VALUE 'validationErrorLog.log',
      lv_cr_lf                      TYPE abap_cr_lf VALUE cl_abap_char_utilities=>cr_lf.

*   Get the path to the temporary directory in order to store
*   all necessary files there as well as to perform the validation there.
    cl_gui_frontend_services=>get_temp_directory(
      CHANGING
        temp_dir             = lv_temp_dir_path    " Temporary Directory
      EXCEPTIONS
        cntl_error           = 1
        error_no_gui         = 2
        not_supported_by_gui = 3
        OTHERS               = 4
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.
    cl_gui_cfw=>flush( ).

    cl_gui_frontend_services=>get_file_separator(
      CHANGING
        file_separator       = lv_filename_separator
    EXCEPTIONS
      not_supported_by_gui = 1
      error_no_gui         = 2
      cntl_error           = 3
      OTHERS               = 4
  ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

*   Setup filename.
    lv_xml_filename = lv_temp_dir_path && lv_filename_separator && lv_xml_filename.
    lv_xml_filename = me->replace_slash( lv_xml_filename ).

    lv_error_log_file_name = lv_temp_dir_path && lv_filename_separator && lv_error_log_file_name.
    lv_error_log_file_name = me->replace_slash( lv_error_log_file_name ).

    lv_schema_file_path = lv_temp_dir_path && lv_filename_separator && lv_schema_filename.
    lv_schema_file_path = me->replace_slash( lv_schema_file_path ).

    lv_validation_script_filename = lv_temp_dir_path && lv_filename_separator && lv_validation_script_filename.
    lv_validation_script_filename = me->replace_slash( lv_validation_script_filename ).

*   Setup validation script.
    lv_validation_script =
      |var FileSysObj = new ActiveXObject("Scripting.FileSystemObject");| && |{ lv_cr_lf }| &&
      |var xmlReader = new ActiveXObject("MSXML2.SAXXMLReader.4.0");| && |{ lv_cr_lf }| &&
      |var xSchema = new ActiveXObject("MSXML2.XMLSchemaCache.4.0");| && |{ lv_cr_lf }| &&
      |var xWriter = new ActiveXObject("MSXML2.MXXMLWriter.4.0");| && |{ lv_cr_lf }| &&
      |var wShell = new ActiveXObject("WScript.Shell");| && |{ lv_cr_lf }| &&
      |var schemaFile = "| && |{ lv_schema_file_path }| && |";| && |{ lv_cr_lf }| &&
      |var xmlFile = "| && |{ lv_xml_filename }| && |";| && |{ lv_cr_lf }| &&
      |xSchema.add("| && |{ lv_target_namespace }| && |", schemaFile);| && |{ lv_cr_lf }| &&
      |xmlReader.putFeature("schema-validation", true);| && |{ lv_cr_lf }| &&
      |xmlReader.putFeature("exhaustive-errors", true);| && |{ lv_cr_lf }| &&
      |xmlReader.putProperty("schemas", xSchema);| && |{ lv_cr_lf }| &&
      |xmlReader.errorHandler = xWriter;| && |{ lv_cr_lf }| &&
      |try \{| && |{ lv_cr_lf }| &&
      |xmlReader.parseURL(xmlFile);| && |{ lv_cr_lf }| &&
      |\} catch (ex) \{| && |{ lv_cr_lf }| &&
      |\}| && |{ lv_cr_lf }| &&
      |str = xmlFile.split(".");| && |{ lv_cr_lf }| &&
      |var errFile = "| && |{ lv_error_log_file_name }| && |";| && |{ lv_cr_lf }| &&
      |var FileObj = FileSysObj.CreateTextFile(errFile,true);| && |{ lv_cr_lf }| &&
      |FileObj.WriteLine(xWriter.output);| && |{ lv_cr_lf }| &&
      |FileObj.Close();|.

    APPEND lv_validation_script TO lt_validation_script_tmp.

*   Store the validation script locally.
    cl_gui_frontend_services=>gui_download(
      EXPORTING
        filename                  = lv_validation_script_filename " Name of file
        filetype                  = 'ASC'    " File type (ASCII, binary ...)
      CHANGING
        data_tab                  = lt_validation_script_tmp "lt_parse_file    " Transfer table
      EXCEPTIONS
        file_write_error          = 1
        OTHERS                    = 2
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

*   Store the XML-schema locally.
    CLEAR lt_string_tab.
    APPEND lv_schema TO lt_string_tab.
    cl_gui_frontend_services=>gui_download(
      EXPORTING
        filename                  = lv_schema_file_path " Name of file
        filetype                  = 'ASC'    " File type (ASCII, binary ...)
      CHANGING
        data_tab                  = lt_string_tab "lt_parse_file    " Transfer table
      EXCEPTIONS
        file_write_error          = 1
        OTHERS                    = 2
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

*   Store the XML locally.
    CLEAR lt_string_tab.
    APPEND lv_xml TO lt_string_tab.
    cl_gui_frontend_services=>gui_download(
      EXPORTING
        filename                  = lv_xml_filename " Name of file
        filetype                  = 'ASC'    " File type (ASCII, binary ...)
      CHANGING
        data_tab                  = lt_string_tab "lt_parse_file    " Transfer table
      EXCEPTIONS
        file_write_error          = 1
        OTHERS                    = 2
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

    cl_gui_frontend_services=>execute(
      EXPORTING
        application            = lv_validation_script_filename " Path and Name of Application
        synchronous            = 'X'    " When 'X': Runs the Application in Synchronous Mode
      EXCEPTIONS
        cntl_error             = 1
        OTHERS                 = 2
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

*   Read errors.
    CLEAR lt_string_tab.
    cl_gui_frontend_services=>gui_upload(
      EXPORTING
        filename                = lv_error_log_file_name    " Name of file
        filetype                = 'ASC'    " File Type (ASCII, Binary)
      CHANGING
        data_tab                = lt_string_tab    " Transfer table for file contents
      EXCEPTIONS
        file_open_error         = 1
        OTHERS                  = 2
    ).
    IF sy-subrc <> 0.
      RAISE validation_not_possible.
    ENDIF.

    DATA lv_line TYPE string.
    LOOP AT lt_string_tab INTO lv_line.
      CONDENSE lv_line.
      IF lv_line IS NOT INITIAL .
        lv_valid = abap_false.
        RETURN.
      ENDIF.
    ENDLOOP.

    lv_valid = abap_true.

Explanation

At first a temporary directory on the client machine is created. Then all necessary file paths are constructed. All files will be stored in the same directory. There will be…

  • one file that is the JScript script file
  • one file for the XML-schema
  • one file for the XML instance to validate
  • one file that contains validation error (after the validation has been performed).

The content of the validation script is constructed just afterwards. Note that the whole processing is XML-namespace aware! I.e. using no or an empty namespace might end up in errors. The first three files are downloaded to the client machine and the validation script is executed synchronously. I.e. the code waits at the call of cl_gui_frontend_services=>execute until the script execution has been finished. Afterwards the error log file is uploaded onto the application server and its content analyzed. The validation script is implemented that way any error will result in a line in the error log file. If there are no entries in the error log, the XML instance is valid with respect to the XML-schema. The following snippet shows the validation script (more readable than in ABAP above):


var FileSysObj = new ActiveXObject("Scripting.FileSystemObject");
var xmlReader = new ActiveXObject("MSXML2.SAXXMLReader.4.0");
var xSchema = new ActiveXObject("MSXML2.XMLSchemaCache.4.0");
var xWriter = new ActiveXObject("MSXML2.MXXMLWriter.4.0");
var wShell = new ActiveXObject("WScript.Shell");
var schemaFile = "C:\\Users\\<user>\\AppData\\Local\\SAP\\SAP GUI\\tmp\\DependencySchema.xsd";
var xmlFile = "C:\\Users\\<user>\\AppData\\Local\\SAP\\SAP GUI\\tmp\\xmlToValidate.xml";
xSchema.add("http://sap.com/XYZ", schemaFile);
xmlReader.putFeature("schema-validation", true);
xmlReader.putFeature("exhaustive-errors", true);
xmlReader.putProperty("schemas", xSchema);
xmlReader.errorHandler = xWriter;
try {
xmlReader.parseURL(xmlFile);
} catch (ex) {
}
str = xmlFile.split(".");
var errFile = "C:\\Users\\<user>\\AppData\\Local\\SAP\\SAP GUI\\tmp\\validationErrorLog.log";
var FileObj = FileSysObj.CreateTextFile(errFile,true);
FileObj.WriteLine(xWriter.output);
FileObj.Close();



Note that the used XML-schema should look like this for the current example:


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified"
          elementFormDefault="qualified" xmlns="http://sap.com/XYZ"
          targetNamespace="http://sap.com/XYZ">
    <!-- insert schema details here -->
</xs:schema>


If an error occurs during validation it looks like this (example):

Error:
Line Number: 1
Column Number: 34120
SystemId: "file:///C:/Users/<user>/AppData/Local/SAP/SAP%20GUI/tmp/xmlToValidate.xml"
PublicId: ""
Description: Validate failed because the root element had no associated DTD/schema.

Error Code: -2147467259

Availability

Key Value
Software Component SAP_BASIS                                                                  
Requires Client-Side Software Library Yes
Required Client-Side Software Libraries MSXML 3.0 or later
Code Snippet is OS dependent Yes
Required OS MS Windows
To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply