Pregunta

Debe haber una forma genérica de transformar algún XML jerárquico como:

<element1 A="AValue" B="BValue">
   <element2 C="DValue" D="CValue">
      <element3 E="EValue1" F="FValue1"/>
      <element3 E="EValue2" F="FValue2"/>
   </element2>
   ...
</element1>

en el XML aplanado (html) recogiendo atributos seleccionados a lo largo del camino y proporcionando diferentes etiquetas para los atributos que se convierten en encabezados de columna.

<table>
   <tr>
     <th>A_Label</th>
     <th>D_Label</th>
     <th>E_Label</th>
     <th>F_Label</th>
   </tr>
   <tr>
     <td>AValue</td>
     <td>DValue</td>
     <td>EValue1</td>
     <td>FValue1</td>
   </tr>
   <tr>
     <td>AValue</td>
     <td>DValue</td>
     <td>EValue2</td>
     <td>FValue2</td>
   </tr>
<table>

Bien, entonces no hay una solución genérica debido al reetiquetado de atributos, pero espero que entiendas lo que quiero decir.Acabo de comenzar con todo el material XSLT/XPATH, así que lo resolveré a su debido tiempo, pero cualquier pista sería útil.

¿Fue útil?

Solución

No estoy 100% seguro de lo que intenta hacer, pero esta solución puede funcionar si su elemento1, elemento2 y elemento3 están anidados de manera consistente.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <table>
            <xsl:apply-templates select="//element3"></xsl:apply-templates>
        </table>
    </xsl:template>

    <xsl:template match="element3">
        <tr>
            <td><xsl:value-of select="../../@A"/></td>
            <td><xsl:value-of select="../../@B"/></td>
            <td><xsl:value-of select="../@C"/></td>
            <td><xsl:value-of select="../@D"/></td>
            <td><xsl:value-of select="@E"/></td>
            <td><xsl:value-of select="@F"/></td>
        </tr>
        <xsl:apply-templates select="*"></xsl:apply-templates>
    </xsl:template>

</xsl:stylesheet>

Otros consejos

Necesitaba un XSLT similar pero con una profundidad desconocida, así es como lo hice.

Primero, agregue un contenedor para la tabla HTML/lista de definiciones resultante y llame a la plantilla mode="puke" para aplanar nuestro árbol XML:

<xsl:element name="div">
    <xsl:attribute name="class" select="puke" />
    <xsl:apply-templates select="$notice" mode="puke" />
</xsl:element>  

Aquí hacemos coincidir cada nodo para mostrar su contenido (p. ej.text()) y sus atributos.Hacemos esto de forma recursiva.Utilicé dl/dt/dd porque mi árbol fuente era un árbol complejo que no se puede aplanar como un archivo .

<!-- @description: 
    Display all field from the notice so the customer can tell what he want
-->
<xsl:template match="node()" mode="puke">
<xsl:message>
    puking : <xsl:value-of select="local-name( . )" />
</xsl:message>
    <xsl:element name="dl">
        <xsl:element name="dt">
            <xsl:attribute name="class">tagName</xsl:attribute> 
            <xsl:value-of select="local-name( . )" />
        </xsl:element>
        <xsl:element name="dd">
            <xsl:attribute name="class">tagText</xsl:attribute>
            <xsl:value-of select="text()" /></xsl:element> 
        <xsl:element name="dl">
            <xsl:attribute name="class">attr</xsl:attribute>
            <!-- display attribute -->
            <xsl:apply-templates select="@*" />
        </xsl:element>
    </xsl:element>
    <!-- recursive call on node() -->
    <xsl:apply-templates select="./*" mode="puke" />    
</xsl:template>

Haga coincidir el atributo de un nodo determinado y muéstrelo.

El CSS se utiliza para formatear el HTML resultante:

<style>
.puke {
    background-color: #BDD6DE;
    clear: both;
}
.tagName, .attrName {
    float: left;
}
.tagText, .attrText {
    clear: right;
}
</style>

Ya tenemos un programa Pro*C que lee desde una base de datos Oracle, llama a un script perl que a su vez ejecuta algo de Java para extraer datos en formato XML de la base de datos antes mencionada para llamar a un archivo por lotes para ejecutar algún vbscript. Enviar el archivo por FTP a otro servidor.Realmente esperaba algo en Fortran.

Es necesario aclarar la pregunta original:

  • ¿Qué pasa con BValue y CValue en la pregunta original?¿Hay alguna razón por la que no deberían ser parte de la estructura aplanada?
  • ¿Todos los elementos del documento XML tienen 2 atributos o es completamente arbitrario?
  • ¿Existen solo 3 tipos de elementos y siempre están anidados como se muestra en el ejemplo?
  • ¿Se puede repetir su elemento 1 o es este el elemento raíz de su documento?

En XSLT es posible escribir transformadores muy genéricos, pero suele ser mucho más fácil escribir una hoja de estilo para transformar un documento cuando se pueden tener en cuenta las restricciones conocidas.

He utilizado una versión ampliada de la plantilla siguiente para aplanar XML estructurado.Advertencia:Había un código específico de cada caso en la versión original (en realidad convirtió el XML en CSV) que simplemente eliminé y no probé esta versión.

La forma básica en que funciona debe quedar clara:imprime todo lo que no tiene hijos de nodo y, de lo contrario, llama recursivamente a la plantilla en el nodo() que sí tiene hijos.No creo que maneje atributos y comentarios correctamente como lo hace ahora, pero eso no debería ser difícil de solucionar.

<?xml version="1.0" encoding="UTF-8"?>

<!-- XSL template to flatten structured XML, before converting to CSV. -->
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:strip-space elements="*" /> 

    <xsl:template match="/">
        <xsl:apply-templates select="//yourElementsToFlatten"/>
    </xsl:template>

    <xsl:template match="//yourElementsToFlatten">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:choose>
            <!-- If the element has multiple childs, call this template 
                on its children to flatten it-->
            <xsl:when test="count(child::*) > 0">
                <xsl:apply-templates select="@*|node()"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:value-of select="text()" />
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top