Usando xslt, trasforma un documento XML in base al contenuto di un secondo documento XML

StackOverflow https://stackoverflow.com/questions/647324

  •  22-07-2019
  •  | 
  •  

Domanda

Ho una serie di documenti che definiscono implicitamente i campi consentiti per una seconda serie di oggetti che devono essere trasformati in una terza serie di documenti ( quale "regole" il documento da utilizzare dipende dal contenuto del file da trasformare) ad es.

<!-- One example rules document --> 
<document object="obj1_rules">
<field name="A"/>
<field name="B"/>
<field name="C"/>
</document>

<!-- Document to be tranformed based upon obj1_rules--> 
<document object="obj1">
<field name="A"/>
<field name="B"/>
<field name="C"/>
<field name="D"/>
<field name="E"/>
</document>

<!-- Desired result--> 
<document object="obj1">
<newfield name="A"/>
<newfield name="B"/>
<newfield name="C"/>
</document>

È possibile effettuare questa trasformazione usando xslt?

Vedo che " Non c'è modo in XSLT di costruire espressioni XPath (ad es. riferimenti variabili) in fase di esecuzione. " Quindi sono sfortunato o sto solo guardando questo problema in modo errato? Grazie!

È stato utile?

Soluzione

Ecco una soluzione semplice :

Questa trasformazione :

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
<!--                                                   -->  
    <xsl:variable name="vrtfRules">
        <document object="obj1_rules">
            <field name="A"/>
            <field name="B"/>
            <field name="C"/>
        </document>
    </xsl:variable>
<!--                                                   -->  
    <xsl:variable name="vRules" select=
     "document('')/*/xsl:variable
                   [@name = 'vrtfRules']
                     /*
     "/>
<!--                                                   -->  
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
<!--                                                   -->  
    <xsl:template match="field">
      <xsl:if test="@name = $vRules/*/@name">
        <newfield>
          <xsl:apply-templates select="node()|@*"/>
        </newfield>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

quando applicato sul documento XML di origine fornito originariamente:

<document object="obj1">
    <field name="A"/>
    <field name="B"/>
    <field name="C"/>
    <field name="D"/>
    <field name="E"/>
</document>

produce il risultato desiderato:

<document object="obj1">
   <newfield name="A"/>
   <newfield name="B"/>
   <newfield name="C"/>
</document>

Nota che il documento "quot regole" " è all'interno del foglio di stile solo per compattezza. Quando si tratta di un documento separato, solo il document () la funzione utilizzata dovrà essere modificata con l'attuale href .

Altri suggerimenti

Forse sto semplificando troppo, ma c'è un motivo per cui il tuo documento "regole" " non può essere semplicemente un XSLT?

Bene, posso capire perché ti piacerebbe avere delle regole in un semplice file xml piuttosto che in un foglio di stile xsl completo ma stai semplicemente saltando un passo.

Devi creare un foglio di stile xsl che trasformerà il tuo documento di regole xml in un foglio di stile xsl che dovrai quindi applicare al tuo XML di origine.

Il trucco è con gli spazi dei nomi e non confondersi con il mix di regole xsl applicate e regole xsl generate.

    <?xml version="1.0" ?>
    <xsl:stylesheet
        xmlns="YOUR_NAMESPACE_HERE"
        xmlns:output="http://www.w3.org/1999/XSL/Transform"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">

        <xsl:output
            method="xml"
            indent="yes"
            media-type="text/xsl" />

        <xsl:template match="/">
            <output:stylesheet version="2.0">
                <xsl:apply-templates />
            </output:stylesheet>
        </xsl:template>

        <xsl:template match="document[@object]">
            <output:template match="document[@object='{@object}']">
                <output:copy>
                    <xsl:apply-templates />
                </output:copy>
            </output:template>
        </xsl:template>

        <xsl:template match="field[@name]">
            <output:if test="field[@name='{@name}']">
                <output:copy-of select="field[@name='{@name}']" />
            </output:if>
        </xsl:template>

    </xsl:stylesheet>

Ho presunto che avresti usato lo stesso attributo oggetto documento nelle regole e nei documenti stessi (questo è molto più semplice imo).

Quindi, esegui il tuo documento delle regole attraverso il foglio di stile sopra. Il risultato è un nuovo foglio di stile xsl che fa esattamente ciò che descrivi nel documento della regola xml. Quindi applica questo foglio di stile risultante sul documento di origine e dovresti ottenere il risultato che ti aspetti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top