Los ficheros realizados con lenguaje XML son muy comunes a la hora de intercambiar información entre diferentes sistemas. Es un lenguaje estándar fácil de entender, pero dependiendo de la complejidad del fichero la transformación puede volverse complicada. En este artículo explicaremos cómo transformar la información de un XML de varios niveles a ABAP para poder tratar esos datos.

Para poder explicar el funcionamiento de la transformación utilizaremos un ejemplo. El fichero XML utilizado en el artículo tiene el siguiente formato:

<DatosReceptoresEf4ktur>
    <DatosReceptor>
        <RazonSocial></RazonSocial>
        <Direccion></Direccion>
        <CodigoPostal></CodigoPostal>
        <Poblacion></Poblacion>
        <Provincia></Provincia>
        <Correo></Correo>
        <ContactoAdicional></ContactoAdicional>
        <CorreoEnvio></CorreoEnvio>
        <DescripcionDepartamento></DescripcionDepartamento>
        <Departamento></Departamento>
        <CIF></CIF>
        <DatosContratante>
            <CentroAdministrativo>
                <CentreCode></CentreCode>
                <CentreDescription></CentreDescription>
                <RoleTypeCode></RoleTypeCode>
                <CodigoEntidadRelacionada></CodigoEntidadRelacionada>
                <Name></Name>
                <FirstSurname></FirstSurname>
                <SecondSurname></SecondSurname>
                <Address></Address>
                <PostCode></PostCode>
                <Town></Town>
                <Province></Province>
                <Pais></Pais>
                <ElectronicMail></ElectronicMail>
                <Telephone></Telephone>
            </CentroAdministrativo>
        </DatosContratante>
    </DatosReceptor>
</DatosReceptoresEf4ktur>

En el fichero habrá varios datos de receptores, y dentro de los datos contratantes podrá haber varios centros administrativos. También puede darse el caso de que un receptor no tenga ningún centro administrativo. Para poder importar los datos lo dividiremos en dos partes:

  • la creación de objetos del diccionario ABAP
  • la creación de la transformación

 

Creación de los objetos del diccionario ABAP

Nuestro objetivo en la SE11 es crear un tipo de tabla que tenga una estructura la cual pueda contener todos los campos que tiene el XML.

Actualizar tipo de tablas para transformaciones XML complejos a ABAP

SAP: estructura XML a ABAP

Si nos fijamos en la imagen el último campo de la estructura es otro tipo de tabla. Este tipo de tabla tendrá que tener una estructura para poder guardar todo lo que hay dentro de las etiquetas “DatosContratante”, es decir, todos los centros administrativos.

SAP: estructura XML a ABAPSAP: estructura XML a ABAP

También, habría que crear, los dominios y elementos de datos necesarios para cada campo, en caso de no poder reutilizar otros ya creados.

Creación de la transformación

Una vez creados todos los objetos necesarios para albergar los datos del XML tendremos que realizar la transformación. Las transformaciones se crean en la transacción STRANS. Al darle al botón crear nos pedirá una descripción y la clase de transformación. La clase que elegiremos será “Transformación Simple”.

SAP: Transformación simple XML

Para crear la lógica de la transformación utilizaremos el modo gráfico pinchando en la varita redondeada en la imagen.

SAP - lógica de transformación simple - XML

Por defecto, nos aparece el elemento “ROOT” que borraremos (click derecho -> delete) para meter la estructura creada por nosotros en la SE11 (click derecho -> Insert new root).

Estructura - root - SAP - XML

De esta manera, se cargará la estructura y podremos arrastrarla a la otra columna para que nos cree la transformación para la plantilla que hemos cargado.

Cargar estructura creada - transformación XML

Prácticamente ya tenemos creada nuestra transformación. Sólo nos falta cambiar algunos elementos para finalizar.

Lo primero será ponerles el mismo nombre a las etiquetas que en el XML. Por ejemplo en el caso de “DatosReceptor” que la etiqueta sale con el nombre “Z……”.

También, el caso de «CorreoEnvio», que en nuestra transformación la etiqueta tiene el nombre SENTMAIL porque es nombre del campo en la estructura creada en la SE11. Si nos fijamos en el código, veremos que dentro de cada etiqueta tenemos asignado el campo en el que se guardará ese valor.

Otro aspecto a tener en cuenta es que las etiquetas son “case sensitive”, así que hay que escribirlos exactamente igual al XML, controlando que coincidan las mayúsculas/minúsculas.

Antes de los cambios:

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates" xmlns:ddic="http://www.sap.com/abapxml/types/dictionary" xmlns:def="http://www.sap.com/abapxml/types/defined">
  <tt:root name="DATOSRECEPTORESEF4KTUR" type="ddic:ZXMLRECEPTOR_TT"/>
  <tt:template>
    <DATOSRECEPTORESEF4KTUR>
      <tt:loop ref=".DATOSRECEPTORESEF4KTUR">
        <ZXMLRECEPTOR_ST>
          <DESCRIPTION tt:value-ref="DESCRIPTION"/>
          <ADDRESS tt:value-ref="ADDRESS"/>
          <POSTCODE tt:value-ref="POSTCODE"/>
          <TOWN tt:value-ref="TOWN"/>
          <PROVINCE tt:value-ref="PROVINCE"/>
          <MAIL tt:value-ref="MAIL"/>
          <MAIL2 tt:value-ref="MAIL2"/>
          <SENTMAIL tt:value-ref="SENTMAIL"/>
          <DEPARTMENTDESCRI tt:value-ref="DEPARTMENTDESCRI"/>
          <DEPARTMENT tt:value-ref="DEPARTMENT"/>
          <CIF tt:value-ref="CIF"/>
          <DATOSCONTRATANTE>
            <tt:loop ref="DATOSCONTRATANTE">
              <ZCENTROADMIN_ST>
                <CENTRECODE tt:value-ref="CENTRECODE"/>
                <DESCRIPTION tt:value-ref="DESCRIPTION"/>
                <ROLETYPE tt:value-ref="ROLETYPE"/>
                <RELATEDENTITY tt:value-ref="RELATEDENTITY"/>
                <NAME tt:value-ref="NAME"/>
                <FIRSTSURNAME tt:value-ref="FIRSTSURNAME"/>
                <SECONDSURNAME tt:value-ref="SECONDSURNAME"/>
                <ADDRESS tt:value-ref="ADDRESS"/>
                <POSTCODE tt:value-ref="POSTCODE"/>
                <TOWN tt:value-ref="TOWN"/>
                <PROVINCE tt:value-ref="PROVINCE"/>
                <COUNTRY tt:value-ref="COUNTRY"/>
                <MAIL tt:value-ref="MAIL"/>
                <PHONE tt:value-ref="PHONE"/>
              </ZCENTROADMIN_ST>
            </tt:loop>
          </DATOSCONTRATANTE>
        </ZXMLRECEPTOR_ST>
      </tt:loop>
    </DATOSRECEPTORESEF4KTUR>
  </tt:template>

Por último, como hemos dicho al principio del artículo, puede que algún receptor no tenga centros administrativos. Por lo tanto, no tendrá la estructura a partir de “DatosContratante”. Para que durante la deserialización de la transformación no nos salte el error de que no encuentra esas etiquetas deberemos añadir la siguiente etiqueta al código de la transformación: <tt:d-cond>. Después de los cambios de nombre anteriores y la condición:

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates" xmlns:ddic="http://www.sap.com/abapxml/types/dictionary" xmlns:def="http://www.sap.com/abapxml/types/defined">
  <tt:root name="DATOSRECEPTORESEF4KTUR" type="ddic:ZXMLRECEPTOR_TT"/>
  <tt:template>
    <DATOSRECEPTORESEF4KTUR>
      <tt:loop ref=".DATOSRECEPTORESEF4KTUR">
        <DatosReceptor>
          <RazonSocial tt:value-ref="DESCRIPTION"/>
          <Direccion tt:value-ref="ADDRESS"/>
          <CodigoPostal tt:value-ref="POSTCODE"/>
          <Poblacion tt:value-ref="TOWN"/>
          <Provincia tt:value-ref="PROVINCE"/>
          <Correo tt:value-ref="MAIL"/>
          <ContactoAdicional tt:value-ref="MAIL2"/>
          <CorreoEnvio tt:value-ref="SENTMAIL"/>
          <DescripcionDepartamento tt:value-ref="DEPARTMENTDESCRI"/>
          <Departamento tt:value-ref="DEPARTMENT"/>
          <CIF tt:value-ref="CIF"/>
          <tt:d-cond>
          <DATOSCONTRATANTE>
            <tt:loop ref="DATOSCONTRATANTE">
              <CentroAdministrativo>
                <CentreCode tt:value-ref="CENTRECODE"/>
                <CentreDescription tt:value-ref="DESCRIPTION"/>
                <RoleTypeCode tt:value-ref="ROLETYPE"/>
                <CodigoEntidadRelacionada tt:value-ref="RELATEDENTITY"/>
                <Name tt:value-ref="NAME"/>
                <FirstSurname tt:value-ref="FIRSTSURNAME"/>
                <SecondSurname tt:value-ref="SECONDSURNAME"/>
                <Address tt:value-ref="ADDRESS"/>
                <PostCode tt:value-ref="POSTCODE"/>
                <Town tt:value-ref="TOWN"/>
                <Province tt:value-ref="PROVINCE"/>
                <Pais tt:value-ref="COUNTRY"/>
                <ElectronicMail tt:value-ref="MAIL"/>
                <Telephone tt:value-ref="PHONE"/>
              </CentroAdministrativo>
            </tt:loop>
          </DATOSCONTRATANTE>
          </tt:d-cond>
        </DatosReceptor>
      </tt:loop>
    </DATOSRECEPTORESEF4KTUR>
  </tt:template>

De esta manera, si lo que hay dentro de las etiquetas <tt:d-cond> no existe, la transformación lo obviará. No nos saltará ningún error y seguirá con el siguiente receptor. La transformación estaría finalizada, y tan sólo faltaría activarla para poder usarla.

Con lo explicado anteriormente ya tendríamos hecha la transformación del XML para poder pasar la información a ABAP. La forma de poder utilizarla en un report es mediante la sentencia CALL TRANSFORMATION.