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.
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.
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”.
Para crear la lógica de la transformación utilizaremos el modo gráfico pinchando en la varita redondeada en la imagen.
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).
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.
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.
en la transformación estoy creando 1 XLS , ahora lo debo adjuntar para enviarlo por mail , como se puede realizar eso .
se esta ejecutando para el envio del correo es cl_document_bcs
Excelente artículo, muchisimas gracias.
Hola! Como estas?Se puede hacer una transformacion sin leer todos los tag? Ejemplo, de todos los campos solo necesito leer 5. En ese caso, solo colocaria esos 5 campos en la transformacion o deberia colocar todos? Gracias
Buenas Lau
En relación a tu pregunta, es necesario añadir todas la etiquetas en la transformación. Después, puedes usar añadir a tu transformación el elemento skip para que aquellas etiquetas que no te interesen no se pasen a la tabla interna de tu programa ABAP al hacer el CALL TRANSFORMATION. Si no añades todas las etiquetas recibirás un dump indicando que ha encontrado elementos desconocidos.
Esperamos haber sido de ayuda. Muchas gracias por leernos.
Francisco. Como controlar si es al XML que le falta un TAG ¿es posible controlar leer solo las etiquetas que tengo creadas?
Sí, es posible realizar la transformación sin que en XML existan todas las etiquetas que aparecen en la transfromación. Con la etiqueta podemos marcar aquellas etiquetas que son opcionales. De esa forma si la etiqueta no existe seguirá con la transformación, en vez de dar error.
Un saludo
Hola buen día, saben como incluir acentos y la letra Ñ en una transformada?
Antes del call transformation. Lees los datos del fichero en el report mediante OPEN DATASET donde puedes indicar el enconding con el que quieres leer. En mi caso: OPEN DATASET c_xmlFile FOR INPUT IN TEXT MODE ENCODING DEFAULT
Un saludo y gracias por leernos
Buenas, como haces el llenado de DatosContratante
Como pone en el artículo, antes de especificar los campos de datos contratante se añade la etiqueta, ya que, puede haber receptores que no tengan centros administritativos. Después, se añade un loop a los centros administrativos porque cada receptor tiene varios centros administrativos. La parte de la transformación no estaba correctamente formateada. Échale otro vistazo ahora que la indentación es correcta.
Un saludo y gracias por leernos
Hola buenos días,
Soy totalmente novato en temas XML. Gran explicación. Pero me gustaría saber como pasarlo al Abap con la Call Transformation. Es decir, a partir de un fichero plano XML (cargándolo o ya en una itab en Abap), como poder ejecutar la Call Transformation. Siento si dicha pregutna es una pregunta ilógica. Disculpad mi ignorancia en este tema.
Gracias,
Saludos.
Buenos días Francisco,
En nuestro caso utilizamos un OPEN DATASET y un READ DATASET cargamos el fichero xml línea por línea en un string. Una vez leído el XML hago el CALL TRANSFORMATION de la siguiente manera:
Esperemos que te haya servido de ayuda
un saludo