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:
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.
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...
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
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 |