Domanda

Deve esserci un modo generico per trasformare alcuni XML gerarchici come:

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

nell'XML appiattito (html) raccogliendo attributi selezionati lungo il percorso e fornendo etichette diverse per gli attributi che diventano intestazioni di colonna.

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

OK, quindi non esiste una soluzione generica a causa della rietichettatura degli attributi, ma si spera che tu capisca cosa intendo.Ho appena iniziato a lavorare su XSLT/XPATH, quindi lo risolverò in tempo utile, ma qualsiasi indizio sarebbe utile.

È stato utile?

Soluzione

Non sono sicuro al 100% di quello che stai cercando di fare, ma questa soluzione potrebbe funzionare se i tuoi element1, element2 ed element3 sono nidificati in modo coerente.

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

Altri suggerimenti

Avevo bisogno di un XSLT simile ma con una profondità sconosciuta, ecco come l'ho fatto.

Innanzitutto, aggiungi un wrapper per l'elenco di tabelle/def HTML risultante e chiama il template mode="puke" per appiattire il nostro albero XML:

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

Qui abbiniamo ciascun nodo per visualizzarne il contenuto (ad es.text()) e i suoi attributi.Lo facciamo in modo ricorsivo.Ho usato dl/dt/dd perché il mio albero di origine era un albero complesso che non può essere appiattito come un file .

<!-- @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>

Abbina gli attributi di un dato nodo e visualizzali.

Il CSS utilizza per formattare l'HTML risultante:

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

Abbiamo già un programma Pro*C che legge da un database Oracle, chiama uno script perl che a sua volta esegue alcuni Java per estrarre i dati in formato XML dal database di cui sopra per chiamare un file batch per eseguire alcuni vbscript inviando il file tramite FTP a qualche altro server.Speravo davvero in qualcosa in Fortran.

La domanda iniziale deve essere chiarita:

  • Cosa succede con BValue e CValue nella domanda originale?C'è una ragione per cui non dovrebbero far parte della struttura appiattita?
  • Tutti gli elementi nel documento XML hanno 2 attributi o questo è completamente arbitrario?
  • Esistono solo 3 tipi di elementi e sono sempre annidati come mostrato nell'esempio?
  • Il tuo elemento1 può essere ripetuto o è l'elemento radice del tuo documento?

In XSLT è possibile scrivere trasformatori molto generici ma spesso è molto più semplice scrivere un foglio di stile per trasformare un documento quando si possono tenere in considerazione eventuali restrizioni note.

Ho utilizzato una versione ampliata del modello seguente per appiattire l'XML strutturato.Avvertimento:C'era del codice specifico per il caso nella versione originale (in realtà trasformava l'XML in CSV) che ho appena rimosso e non ho testato questa versione.

Il modo in cui funziona di base dovrebbe essere chiaro:stampa tutto ciò che non ha figli di nodi e altrimenti chiama ricorsivamente il modello sul node() che ha figli.Non penso che gestisca correttamente attributi e commenti come lo è ora, ma non dovrebbe essere difficile risolverlo.

<?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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top