Tuesday, April 15, 2014

XML validation for SEPA files inside AX 2009

Introduction

If a SEPA XML file generated by AX 2009 has any errors which will lead to a schema violation, it could be a very annoying situation for the user, if this error is recognized only by the banking software later in the process. Especially when the payment journal is already posted. The only option then is to manually edit the corrupted XML file.
Unfortunately this is the standard situation, because AX 2009 does no additional checks during a SEPA file export. But with some simple enhancements you can implement a XML schema validation inside AX.


Validation class

This is an example of a class for XML validation that can be implemented in the SEPA framework classes.

/// 
/// Class to validate a XML document against a XML schema.
/// 
class XmlValidator
{
    Filename schemaFilename;
    XmlSchema schema;
    XmlDocument xmlDoc;
}

public static XmlValidator construct(Filename _schemaFilename, XmlDocument _xmlDoc)
{
    XmlValidator xmlValidator;
    ;
    xmlValidator = new XmlValidator(_schemaFilename, _xmlDoc);
    if (xmlValidator)
    {
        xmlValidator.loadSchema();
    }
    return xmlValidator;
}

void new(Filename _schemaFilename, XmlDocument _xmlDoc)
{
    ;
    schemaFilename = _schemaFilename;
    xmlDoc = _xmlDoc;
}

/// 
/// Loads a xml schema file from the AOT resource node.
/// 
/// 
/// Throws an error if the ResourceNode object is not instantiated.
/// 
private void loadSchema()
{
    ResourceNode resourceNode;
    Identifiername resourceName;
    BinData data;
    Xml xsd;
    ;
    resourceName = strReplace(schemaFilename, '.', '_');
    resourceNode = SysResource::getResourceNode(resourceName);
    if (resourceNode)
    {
        data = new BinData();
        data.setData(SysResource::getResourceNodeData(resourceNode));
        xsd = data.getStrData();
        schema = XmlSchema::newXml(xsd);
    }
    else
    {
        throw error(strfmt("Schema %1: The file could not be loaded.", schemaFilename));
    }
}

public boolean validate()
{
    XmlSchemaValidationError validationError;
    XmlReader xmlReader;
    boolean ret = true;
    ;
    if (schema)
    {
        xmlReader = XMLReader::newXml(xmlDoc.xml());
        if (xmlReader)
        {
            validationError = xmlReader.validate(schema.writeToString());
            if (validationError)
            {
                ret = checkFailed(validationError.message());
            }
        }
    }

    return ret;
}
This example loads an schema file directly from the AOT resource node and deals with the fact, that AX replaces dots in the imported file name with underscores (method 'loadSchema'). But you can also use another source for the schema file.


Implementation

This is an example implementation for the SEPA file export in the class 'CustOutPaym_SEPA'.

/// 
///  Saves totals on message, closes the file and prints control report.
/// 
public void close()
{
    this.updateXmlHeaderTotals();
    if (numOfRecords != 0)
    {
// 
        if (!this.validateXml())
        {
            throw error("SEPA file creation aborted.");
        }
// 
        CustOutPaym_SEPA::saveXMLOnClient(xmlDoc, filename);
    }
    this.printControlReport();
}

protected boolean validateXml()
{
    XmlValidator xmlValidator = XmlValidator::construct(this.schema() + '.xsd', xmlDoc);
    ;
    if (xmlValidator)
    {
        return xmlValidator.validate();
    }
    return checkFailed("XML file validation could not be executed.");
}
The validation can only take place if the XML string is completely generated. Because of the special design of the CustVendOutPaym class hierarchy, the payment status is already changed and committed to the database at this time. So if the XML file is not written to file system because of an identified schema error, the user can change the status of the payment journal lines back to "None" again, correct the cause of the problem and run the file generation again.

Other possible classes for the implementation are
  • VendOutPaym_SEPA
  • VendOutPaym_SEPA03
Download XPO Source file with the examples including the following schema files as AX resource objects.

  • pain.001.001.02.xsd
  • pain.001.001.03.xsd
  • pain.001.002.02.xsd
  • pain.001.002.03.xsd
  • pain.001.003.03.xsd
  • pain.002.002.02.xsd
  • pain.002.003.03.xsd
  • pain.008.001.01.xsd
  • pain.008.001.02.xsd
  • pain.008.002.01.xsd
  • pain.008.002.02.xsd
  • pain.008.003.01.xsd