Frage

Ich bin versucht, eine Transformation auf einem XML-Dokument zu tun. Meine XML kann auf zwei verschiedene Arten von Basiselement je nach dem Wert eines bestimmten Elements Transformation führen:

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'">
      <xsl:call-template name="StructureA">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="StructureB">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

StructureA oder StructureB werden dann mit ihrem eigenen Namensraum und schemaLocations erstellt:

<StructureA xmlns="http://...">

StructureA & B teilen einige gemeinsame Elemente, so dass diese in einer separaten Datei definiert werden als „xmlcommon.xslt“, dass beide Strukturen umfassen Vorlagen aus. Diese xmlcommon Datei nicht über einen Standard-Namespace definiert, wie ich es möchte entweder StructureA oder StructureB definiert aus dem Namensraum nutzbar sein. Aber wenn ich betreibe meine verwandeln, werden alle Vorlagen gezogen aus der gemeinsamen Datei Ergebnis in leere xmlns Attribute:

<StructureA xmlns="http://...">
  <SharedElement xmlns="">Something</SharedElement>
</StructureA>

Bei der Validierung wird die Rohling Namespace dann eine anstelle den richtig Eltern verwendet. Wer weiß, wie ich meine Vorlagen in meiner gemeinsamen Datei von Hinzufügen dieser leere Xmlns stoppen kann Attribute?

Hier ist ein Ausschnitt aus der gemeinsamen Datei:

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="ControlledListStructure">
    <xsl:param name="xmlElem" />
    <xsl:param name="structure" />

    <xsl:element name="{$xmlElem}">
      <!-- Blah blah blah -->
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
War es hilfreich?

Lösung

Der Schlüssel ist daran zu erkennen ist, dass Ihr Sheet den Namen jedes Elements diktiert Sie in den Ergebnisbaum hinzuzufügen. Ein Element Name besteht aus zwei Teilen: den lokalen Namen und der Namespace-URI. In Ihrem Code oben, liefern Sie den lokalen Namen (der Wert von $xmlElem), aber Sie keinen NamespaceURI geben, was bedeutet, es auf die leere Zeichenfolge nicht erfüllt. (Eigentlich dauert es auf dem Standard-Namespace der Sheet-Modul;., Da es keine gibt, dann ist es die leere Zeichenkette) Mit anderen Worten, wird das Element nicht in einem Namespace . Wenn das Dokument Serialisierung muss der XSLT-Prozessor die xmlns="" un-Erklärungen enthalten, um den Standard-Namespace undeclare, die an der Spitze erscheint. Andernfalls würde das Element auf diesem Namensraum, das ist nicht das, was Ihr Sheet diktiert. Die schonendste Weg, dies zu fixieren wäre ein weiterer Parameter hinzuzufügen (z $namespaceURI), genauso wie Sie mit $xmlElem haben. Dann würden Sie schreiben:

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}">

Nun wird das resultierende Element wird auf nehmen, was auch immer Namespace Sie sagen, es zu übernehmen (was den Effekt der Beseitigung dieser Standard-Namespace un-Erklärungen haben).

Das soll Ihre Frage beantworten. Ich biete das folgende als freie Bonusmaterial. ; -)

Sie sollten den text() Knotentest im Wertvergleich entfernen. Sehr selten werden Sie brauchen, um direkt die Werte von Textknoten zu vergleichen. Stattdessen können Sie nur den String-Wert des Elements vergleichen selbst (die als die Verkettung der Zeichenfolge-Werte aller untergeordneten Textknoten definiert ist). Das würde wie folgt aussehen:

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'">

Der Vorteil es auf diese Art und Weise zu tun, ist, dass der Code nicht brechen, wenn es um einen Kommentar ist da drin versteckt:

<value>2<!--test-->00</value>

In diesem Fall gibt es zwei Textknoten ( „2“ und „00“). Ihr Original-Test fehlschlagen würde, da sie überprüft, um zu sehen, ob einer von ihnen gleich „200“. Nicht sehr wahrscheinlich in diesem Fall geschehen, aber in jedem Fall der Prüfung des String-Wertes des Elements (im Gegensatz zu seinem Textknoten Kindern im Gegensatz) ist eine gute Praxis, wenn das Ihre Absicht.

Schließlich, ermutige ich Sie über Template-Regeln und XPath Kontext zu lernen. Ich neige dazu, zu vermeiden <xsl:choose>, <xsl:call-template> und <xsl:with-param> wann immer möglich. Für eine Sache, können Template-Regeln helfen, eine Menge von den hässlichen, ausführlichen Teilen von XSLT zu vermeiden.

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1">
  <StructureA xmlns="http://...">
    ...
  </StructureA>
</xsl:template>

<xsl:template match="/databean">
  <StructureB xmlns="http://...">
    ...
  </StructureB>
</xsl:template>

Auch wenn Sie mit <xsl:call-template> halten, sollen Sie nicht, dass $structure Parameter übergeben müssen, da der aktuelle Knoten wird in der aufgerufenen Vorlage unverändert bleiben. Sie können //databean zugreifen (oder /databean, was ich vermute, ist, was du meinst) genauso einfach von innen entweder Ihren StructureA oder StructureB Vorlagen, weil der aktuelle Knoten noch „/“ (das Dokument Knoten) sein wird.

Wenn Sie interessiert sind, mehr über XSLT Kernverarbeitungsmodell zu lernen, und seine mächtigsten Funktionen (Template-Regeln), dann ich Sie ermutigen, eine href zu überprüfen <= "http://lenzconsulting.com/how-xslt -Werk“rel = "noreferrer"> "Wie XSLT Works" , die freie Probe Kapitel aus meinem XSLT 1.0 Pocket Reference .

Ich hoffe, dass dies für Sie hilfreich war, auch wenn es mehr als Sie! Verhandelte

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top