Frage

Ich habe mit dem Schreiben etwas XSLT 2.0 zu übersetzen ein XML-Dokument in ein anderes XML-Dokument beauftragt. Ich bin relativ neu in XSLT, aber ich habe lernen eine Menge während der Tage, die ich dies zu tun haben. Während dieser Zeit habe ich einfach Werte abbilden mussten, das heißt 002 -> TH usw. für kleine Listen von weniger als 10 Werte in Ordnung war, benutzte ich xsl: wählen. Allerdings brauche ich mehr als 300 Werte aus einer Liste in einer anderen und umgekehrt kartieren. Jede Liste hat einen Wert und Textbeschreibung. Die beiden Listenwerte nicht immer direkt abzubilden, so kann ich textuellen Beschreibungen vergleichen müssen und Standardwerte bei Bedarf verwendet werden.

Ich habe zwei Lösungen für das Problem:

  1. Mit xsl: wählen: Das denke ich könnte eine der beiden Listen Veränderungen langsam und möglichst hart zu aktualisieren, wenn

  2. .
  3. Haben Sie ein XML-Dokument mit der Beziehung zwischen dem einzelnen Listenelement. Ich würde eine XPath-Ausdrücke verwenden, um einen zugehörigen Wert abzurufen: Dies ist meine bevorzugte Lösung, weil ich glaube, dass wird mehr wartbar und einfacher zu aktualisieren. Obwohl ich bin mir nicht sicher, dass es effizient ist.

Welche Lösung sollte ich, einer meiner Anregung, oder gibt es einen besseren Weg, diese Werte abzubilden?

War es hilfreich?

Lösung

Hier ist eine XSLT 2.0-Lösung .

Quelle XML-Datei:

<input>
  <data>001</data>
  <data>002</data>
  <data>005</data>
</input>

"Mapping" XML-Datei:

<map>
  <default>?-?-?</default>
    <input value="001">RZ</input>
    <input value="002">TH</input>
    <input value="003">SC</input>
</map>

XSLT-Transformation:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:param name="pmapFile" 
       select="'C:/temp/deleteMap.xml'" />

  <xsl:variable name="vMap" 
       select="document($pmapFile)" />

  <xsl:variable name="vDefault" 
       select="$vMap/*/default/text()" />

  <xsl:key name="kInputByVal" match="input" 
   use="@value" />

  <xsl:template match="/*">
    <output>
      <xsl:apply-templates/>
    </output>
  </xsl:template>

  <xsl:template match="data">
    <data>
        <xsl:sequence select= 
         "(key('kInputByVal', ., $vMap)[1]/text(),
           $vDefault
           )[1]
         "/>
    </data> 
  </xsl:template>
</xsl:stylesheet>

Ausgabe:

<output>
  <data>RZ</data>
  <data>TH</data>
  <data>?-?-?</data>
</output>

ist folgendes zu beachten: :

  1. Die Verwendung der document() Funktion , um das "Mapping" XML-Dokument, das in einer separaten XML-Datei gespeichert wird.

  2. Die Verwendung von <xsl:key/> und der XSLT 2.0 key() Funktion zu bestimmen, und jeden entsprechenden Ausgang zugreifen Wert. Das dritte Argument gibt das XML-Dokument auf die zugegriffen und indiziert werden müssen.

Andere Tipps

Hier ist eine Art und Weise zu tun, was Sie beabsichtigen, eine <xsl:key> verwenden und sonst nach Ihrer Methode zwei.

Die Beispieleingabedatei (data.xml):

<?xml version="1.0" encoding="utf-8"?>
<input>
  <data>001</data>
  <data>002</data>
  <data>005</data>
</input>

Die Probe Map-Datei (map.xml):

<?xml version="1.0" encoding="utf-8"?>
<map default="??">
  <entry key="001">RZ</entry>
  <entry key="002">TH</entry>
  <entry key="003">SC</entry>
</map>

Die Probe XSL-Stylesheet, Erklärung folgt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes"/>

  <xsl:param name="map-file" select="string('map.xml')" />
  <xsl:variable name="map-doc" select="document($map-file)" />
  <xsl:variable name="default-value" select="$map-doc/map/@default" />
  <xsl:key name="map" match="/map/entry" use="@key" />

  <xsl:template match="/input">
    <output>
      <xsl:apply-templates select="data" />
    </output>
  </xsl:template>

  <xsl:template match="data">
    <xsl:variable name="raw-value" select="." />
    <xsl:variable name="mapped-value">
      <xsl:for-each select="$map-doc">
        <xsl:value-of select="key('map', $raw-value)" />
      </xsl:for-each>
    </xsl:variable>
    <data>
      <xsl:choose>
        <xsl:when test="$mapped-value = ''">
          <xsl:value-of select="$default-value" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$mapped-value" />
        </xsl:otherwise>
      </xsl:choose>
    </data>
  </xsl:template>
</xsl:stylesheet>

Was das bedeutet ist:

  • Verwendung document() map.xml zu öffnen, die resultierende Knotenmenge auf eine Variable Speichern
  • Sie den Standardwert für eine weitere Referenz speichern
  • bereiten eine <xsl:key> arbeiten gegen die „Karte“ Knotensatz
  • Verwendung <xsl:for-each> nicht als Schleife, sondern als Mittel, um den Ausführungskontext zu wechseln, bevor die key() Funktion aufrufen - sonst key() funktionieren würde, gegen das „Daten“ Dokument und kehrt nichts
  • finden den entsprechenden Knoten mit der key() Funktion, speichern Sie es in einer Variablen
  • Überprüfen Sie die Variable Wert auf Ausgang - wenn er leer ist, verwenden Sie den Standardwert
  • Wiederholung (durch <xsl:apply-templates>)

Der Kredit für den ordentlich <xsl:for-each> Trick geht an Jeni Tennison , der die Technik auf der XSL-Mailing-Liste beschrieben. Achten Sie darauf, den Faden zu lesen.

Ausgabe des Stylesheets gegen data.xml ausgeführt wird:

<?xml version="1.0" encoding="utf-8"?>
<output>
  <data>RZ</data>
  <data>TH</data>
  <data>??</data>
</output>

All dies ist XSLT 1.0. Ich bin überzeugt, eine bessere / elegantere Version besteht, dass die Nutzung der Vorteile XSLT 2.0 Angebote macht, aber leider bin ich nicht allzu vertraut mit XSLT 2.0. Vielleicht hat jemand anderes eine bessere Lösung postet.


EDIT

Durch Dimitre Novatchev des Hinweis in den Kommentaren, konnte ich einen ein wesentlich kürzeren und stärker bevorzugt Sheet erstellen:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes"/>

  <xsl:param name="map-file" select="string('map.xml')" />
  <xsl:variable name="map-doc" select="document($map-file)" />
  <xsl:variable name="default" select="$map-doc/map/default[1]" />
  <xsl:key name="map" match="/map/entry" use="@key" />

  <xsl:template match="/input">
    <output>
      <xsl:apply-templates select="data" />
    </output>
  </xsl:template>

  <xsl:template match="data">
    <xsl:variable name="raw-value" select="." />
    <data>
      <xsl:for-each select="$map-doc">
        <xsl:value-of select="(key('map', $raw-value)|$default)[1]" />
      </xsl:for-each>
    </data>
  </xsl:template>
</xsl:stylesheet>

Dies erfordert jedoch eine eine etwas andere Map-Datei in XSLT arbeitet 1.0:

<?xml version="1.0" encoding="utf-8"?>
<map>
  <entry key="001">RZ</entry>
  <entry key="002">TH</entry>
  <entry key="003">SC</entry>
  <!-- default entry must be last in document -->
  <default>??</default>
</map>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top