Vra

Ek probeer om 'n transformasie op 'n XML-dokument te doen.My XML-transformasie kan twee verskillende tipes basiselement tot gevolg hê, afhangende van die waarde van 'n sekere element:

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

StruktuurA of StruktuurB word dan geskep met hul eie naamruimtes en skemaliggings:

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

StruktuurA en B deel 'n paar algemene elemente, so dit word gedefinieer in 'n aparte lêer genaamd "xmlcommon.xslt" waarvan beide strukture sjablone insluit.Hierdie xmlcommon-lêer het nie 'n verstek naamspasie gedefinieer nie, aangesien ek wil hê dit moet bruikbaar wees vanaf die naamspasie wat in StructureA of StructureB gedefinieer is.Maar wanneer ek my transformasie uitvoer, lei enige sjablone wat uit die algemene lêer ingetrek word tot leë xmlns-kenmerke:

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

By die validering word die leë naamspasie dan gebruik in plaas van die korrekte ouer een. Weet iemand hoe ek kan keer dat my sjablone in my algemene lêer daardie leë xmlns-kenmerke byvoeg?

Hier is 'n brokkie uit die algemene lêer:

<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>
Was dit nuttig?

Oplossing

Die belangrikste ding om te besef is dat jou stylblad die naam dikteer van elke element wat jy by die resultaatboom voeg.'n Element se naam het twee dele:die plaaslike naam en die naamruimte-URI.In jou kode hierbo verskaf jy die plaaslike naam (die waarde van $xmlElem), maar jy spesifiseer nie 'n naamruimte-URI nie, wat beteken dat dit die leë string as verstek sal gebruik.(Eintlik neem dit die verstek naamruimte van daardie stylbladmodule aan;aangesien daar geen is nie, dan is dit die leë string.) Met ander woorde, die element sal wees nie in 'n naamruimte nie.Wanneer die dokument serialiseer word, moet die XSLT-verwerker die xmlns="" un-declarations om die verstek naamruimte wat boaan verskyn te ontdeclareer.Andersins sal die element daardie naamruimte aanneem, wat nie is wat jou stylblad gedikteer het nie.Die minste indringende manier om dit reg te stel is om nog 'n parameter by te voeg (bv. $namespaceURI), net soos jy met $xmlElem.Dan skryf jy:

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

Nou, die resulterende element sal enige naamspasie aanneem wat jy ook al aansê om dit aan te neem (wat die effek sal hê om daardie verstek naamruimte-onverklarings te verwyder).

Dit behoort jou vraag te beantwoord.Ek bied die volgende as gratis bonusmateriaal aan.;-)

Jy moet verwyder die text() node toets in jou waarde vergelyking.Baie selde sal jy nodig hê om die waardes van teksnodes direk te vergelyk.In plaas daarvan kan jy net die string-waarde van die element self vergelyk (wat gedefinieer word as die samevoeging van die string-waardes van al sy afstammelinge teks nodes).Dit sou so lyk:

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

Die voordeel om dit op hierdie manier te doen, is dat jou kode nie sal breek as daar 'n opmerking daarin skuil nie:

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

In hierdie geval is daar twee teksnodes ("2" en "00").Jou oorspronklike toets sal misluk, aangesien dit kyk of enige van hulle gelyk is aan "200".Dit is nie baie waarskynlik dat dit in hierdie geval sal gebeur nie, maar in elk geval is die toets van die stringwaarde van die element (in teenstelling met sy teksnoduskinders) 'n goeie praktyk wanneer dit jou bedoeling is.

Ten slotte moedig ek jou aan om meer te wete te kom oor sjabloonreëls en XPath-konteks.Ek is geneig om te vermy <xsl:choose>, <xsl:call-template>, en <xsl:with-param> wanneer moontlik.Vir een ding, sjabloonreëls kan jou help om baie van die lelike, breedvoerige dele van XSLT te vermy.

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

Selfs as jy aanhou gebruik <xsl:call-template>, jy hoef dit nie te slaag nie $structure parameter, aangesien die huidige nodus onveranderd sal bly in die opgeroep sjabloon.Jy kan toegang kry //databean (of /databean, wat ek vermoed is wat jy bedoel) net so maklik van binne enige van jou StructureA of StructureB templates, want die huidige nodus sal steeds "/" (die dokument node) wees.

As jy belangstel om meer te wete te kom oor XSLT se kernverwerkingsmodel en sy kragtigste kenmerke (sjabloonreëls), dan moedig ek jou aan om te kyk "Hoe XSLT werk", die gratis voorbeeld hoofstuk van my XSLT 1.0 Sakverwysing.

Ek hoop dit was nuttig vir jou, al is dit meer as waarvoor jy beding het!

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top