Come ottenere l'output XML desiderato da due XML utilizzando XSLT
Domanda
Sto usando XSLT e XML.
Per prima cosa lavorerò su due xml.
Primo XML:
<?xml version="1.0"?>
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">
<tcm:Item ID="tcm:232-564598" Title="010 News Mapping"/>
<tcm:Item ID="tcm:232-564599" Title="020 CUGOs"/>
<tcm:Item ID="tcm:232-614307" Title="030 Reserved Urls"/>
</tcm:ListItems>
IL Secondo XML lo otterremo utilizzando l'ID sopra, ad es.tcm:232-564598 ecc., di seguito è riportato uno degli xml per l'ID tcm:232-564598 e gli altri ID avranno lo stesso tipo di XML.
<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
<tcm:Data>
<tcm:Content>
<MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
<VanityUrl>
<old>mbp</old>
<new>/SessionHandler.aspx?pageurl=/BP.aspx&pub=/english&section=IBE&j=f</new>
<dateAdded>2010-05-03T14:45:00</dateAdded>
<comments> News mapping </comments>
</VanityUrl>
<VanityUrl>
<old>about/news</old>
<new>about/news/news.aspx</new>
<dateAdded>2010-05-03T14:45:00</dateAdded>
<comments> News mapping </comments>
</VanityUrl>
</MappingCollection>
</tcm:Content>
</tcm:Data>
</tcm:Component>
Sto cercando di ottenere il formato XML inferiore utilizzando entrambi gli XML sopra.
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<!-- News mapping -->
<mapping old="mbp" new="/SessionHandler.aspx?pageurl=/BP.aspx&pub=/english&section=IBE&j=f"/>
<mapping old="about/news" new="about/news/news.aspx"/>
<!-- CUGO's-->
<mapping old="/nhs" new="/cugo.aspx?promoCode=UKNHS01&pub=/uk/english"/>
<mapping old="/hk/ukstudentfare" new="/cugo.aspx?promoCode=HKSTU10&pub=/hk/Chinese"/>
</mappings>
Ed ecco il mio XSLT in cui sto cercando di generare il formato XML sopra ma non funziona per me.tieni presente che il primo xml è l'xml primario che verrà trasformato utilizzando XSLT di seguito
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
<xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>
<!-- root match-->
<xsl:template match="tcm:ListItems">
<mappings>
<xsl:apply-templates select="tcm:Item"/>
</mappings>
</xsl:template>
<xsl:template match="tcm:Item">
<xsl:variable name="doc" select="document(@ID)"/>
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
<xsl:comment>
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
</xsl:comment>
</xsl:if>
<xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
<xsl:element name="mapping">
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old">
<xsl:attribute name="old">
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new">
<xsl:attribute name="new">
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded">
<xsl:attribute name="dateAdded">
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded"/>
</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
In xslt sopra sono in grado di ottenere che anche il ciclo di dati funzioni correttamente, ma i dati che arrivano sono gli stessi, intendo che il ciclo funziona correttamente, ma il valore del nodo è lo stesso
Per favore suggerisci!
Soluzione
Questo foglio di stile:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
xmlns:tcm="http://www.tridion.com/ContentManager/5.0"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="ns tcm msxsl">
<xsl:strip-space elements="*"/>
<xsl:key name="kVanityByComment" match="ns:VanityUrl" use="ns:comments"/>
<xsl:template match="/">
<xsl:variable name="vSourcesRTF">
<xsl:copy-of select="document(tcm:ListItems/tcm:Item/@ID)"/>
</xsl:variable>
<mappings>
<xsl:apply-templates select="msxsl:node-set($vSourcesRTF)/node()"/>
</mappings>
</xsl:template>
<xsl:template match="ns:VanityUrl"/>
<xsl:template match="ns:VanityUrl[generate-id()=
generate-id(key('kVanityByComment',
ns:comments)[1])]">
<xsl:comment>
<xsl:value-of select="ns:comments"/>
</xsl:comment>
<xsl:apply-templates select="key('kVanityByComment',
ns:comments)"
mode="output"/>
</xsl:template>
<xsl:template match="ns:VanityUrl" mode="output">
<mapping>
<xsl:apply-templates/>
</mapping>
</xsl:template>
<xsl:template match="ns:VanityUrl/ns:comments" priority="1"/>
<xsl:template match="ns:VanityUrl/*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Con questo ingresso:
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">
<tcm:Item ID="229-564598" Title="010 News Mapping"/>
<tcm:Item ID="229-564598" Title="020 CUGOs"/>
<tcm:Item ID="229-564598" Title="030 Reserved Urls"/>
</tcm:ListItems>
E questa fonte esterna con 229-564598
URI:
<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
<tcm:Data>
<tcm:Content>
<MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
<VanityUrl>
<old>mbp</old>
<new>/SessionHandler.aspx?pageurl=/BP.aspx&pub=/english&section=IBE&j=f</new>
<dateAdded>2010-05-03T14:45:00</dateAdded>
<comments> News mapping </comments>
</VanityUrl>
<VanityUrl>
<old>about/news</old>
<new>about/news/news.aspx</new>
<dateAdded>2010-05-03T14:45:00</dateAdded>
<comments> News mapping </comments>
</VanityUrl>
</MappingCollection>
</tcm:Content>
</tcm:Data>
</tcm:Component>
Output:
<mappings>
<!-- News mapping -->
<mapping old="mbp"
new="/SessionHandler.aspx?pageurl=/BP.aspx&pub=/english&section=IBE&j=f"
dateAdded="2010-05-03T14:45:00"></mapping>
<mapping old="about/news"
new="about/news/news.aspx"
dateAdded="2010-05-03T14:45:00"></mapping>
</mappings>
Modifica :. Multiple sorgenti di ingresso
Altri suggerimenti
Sì, il cambiamento che hai apportato è davvero fondamentale.:-)
Ciò che fa il ciclo for-each è selezionarli ciascuno <em:VanityUrl>
elemento che corrisponde alla tua espressione XPath, rendi quell'elemento il nodo di contesto per ciò che è all'interno di for-each (chiamato the modello anche se non è un <xsl:template>
), quindi creare un'istanza del modello interno con il nuovo nodo di contesto.
Quando continuavi a utilizzare "$doc/..." all'interno del ciclo for-each, stavi eliminando il nodo di contesto, quindi for-each non aveva alcun effetto (tranne che per ripetere n volte).
Tuo <xsl:if test="$doc/...">
le dichiarazioni stavano valutando se esistesse un nodo del genere nell'intero documento invece che sotto l'elemento contesto <em:VanityUrl>
.
IL <xsl:value-of>
presta attenzione solo al primo nodo nel set di nodi selezionato, quindi ottieni sempre il valore da Primo <em:VanityUrl>
, indipendentemente dal nodo del contesto.
Quando hai iniziato a selezionare e testare rispetto al nodo di contesto:
<xsl:if test="em:old">
tutto è diventato migliore.:-)
Hai chiesto un contributo prezioso.Per ragioni stilistiche, potresti voler sostituire il tuo <xsl:if>
prove con <xsl:apply-templates>
.(Per prima cosa renderai felice @Dimitre Novatchev.:-) COSÌ
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
<xsl:comment>
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
</xsl:comment>
</xsl:if>
diventa
<xsl:apply-templates select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments" />
e quindi hai bisogno di un modello separato per quelli:
<xsl:template match="em:comments">
<xsl:comment>
<xsl:value-of select="."/>
</xsl:comment>
</xsl:template>
Ci sono diversi vantaggi nel farlo.Il più grande è che non è necessario duplicare quella lunga espressione XPath, che era soggetta a errori se l'espressione avesse mai avuto bisogno di essere modificata.Se non ci sono elementi em:comment, i modelli apply-template non faranno nulla, quindi non emetteranno un commento.
Inoltre modularizza il tuo foglio di stile, in modo che tu possa modificare il modo in cui vengono visualizzati em:comments, separatamente da dove possono verificarsi.Ciò potrebbe non avere molta importanza nei documenti XML semplici in cui em:comments si trova in un solo posto, ma è lo stile che sfrutta al meglio la potenza di XSLT.Tieni inoltre presente che questa versione modificata genererà più commenti se sono presenti più em:commenti, cosa che la tua versione non farà.Ancora una volta probabilmente non hai multipli nell'input, quindi potrebbe non avere importanza.
Allo stesso modo per gli attributi di output:
<xsl:if test="em:old">
<xsl:attribute name="old">
<xsl:value-of select="em:old"/>
</xsl:attribute>
</xsl:if>
può diventare
<xsl:apply-templates select="em:old[1]" />
con un modello separato
<xsl:template match="em:old">
<xsl:attribute name="old">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
Notare la [1]
, che evita di tentare di generare output multipli old="..."
attributi per lo stesso elemento se l'input em:VanityUrl ha più elementi em:old.Ciò causerebbe un errore nel tuo foglio di stile.Ma forse tu Volere per sollevare un errore in quel caso.Se è così, probabilmente stai già convalidando il tuo XML di input.
In effetti, puoi generalizzare qui apply-templates e template per applicarli a tutti e tre gli attributi:
<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" />
Ancora una volta, se uno qualsiasi di questi elementi non è presente, non verrà fatto nulla per esso (non verrà prodotto alcun attributo vuoto).Il template:
<xsl:template match="em:old | em:new | em:dateAdded">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
local-name()
ci dà il nome dell'elemento, senza il prefisso dello spazio dei nomi.
Aggiornamento:
Un altro modo per gestirlo sarebbe utilizzare una modalità:
<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]"
mode="make-attribute" />
<xsl:template match="em:*" mode="make-attribute">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
Quindi il tuo modello di attributo può essere utilizzato da qualsiasi luogo e il modello di corrispondenza non deve essere aggiornato per corrispondere a ogni possibile elemento da cui potresti voler creare un attributo.
L'unica altra cosa che vorrei dire è che l'uso degli spazi dei nomi sopra è fonte di confusione... non dovrebbe funzionare così com'è.Per esempio.il tuo foglio di stile utilizza questo URI dello spazio dei nomi per elementi come VanityURL:
"http://www.espire.com/tridion/schemas"
ma il secondo documento di input utilizza questo URI dello spazio dei nomi per quegli elementi:
"uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
Non importa che i prefissi dello spazio dei nomi siano diversi ("em:" vs.default), ma gli URI dello spazio dei nomi devono corrispondere.Immagino che l'URI dello spazio dei nomi di VanityURL debba essere cambiato, altrimenti il tuo foglio di stile non funzionerebbe...
HTH!
Si può provare anche questo !!
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
<xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>
<!-- root match-->
<xsl:template match="tcm:ListItems">
<mappings>
<xsl:apply-templates select="tcm:Item"/>
</mappings>
</xsl:template>
<xsl:template match="tcm:Item">
<xsl:variable name="doc" select="document(@ID)"/>
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
<xsl:comment>
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
</xsl:comment>
</xsl:if>
<xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
<xsl:element name="mapping">
<xsl:if test="em:old">
<xsl:attribute name="old">
<xsl:value-of select="em:old"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="em:new">
<xsl:attribute name="new">
<xsl:value-of select="em:new"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="em:dateAdded">
<xsl:attribute name="dateAdded">
<xsl:value-of select="em:dateAdded"/>
</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>