.net - transformar - xslcompiledtransform
Diseños XSLT con región de contenido dinámico (4)
Estoy trabajando en la reconstrucción de la parte de la interfaz de usuario de nuestro sitio web, que está totalmente basada en javascript / ajax (sin una buena razón y de una manera bastante ineficiente) de manera que el servidor ahora hará la mayor parte de la generación de contenido. Es una aplicación C # .net.
Casi todas nuestras páginas (que probablemente tienen entre 40 y 50 páginas) tienen el mismo diseño básico. Soy nuevo en XSLT pero he trabajado mucho con frameworks MVC como Spring (java, usando Sitemesh para maquetación), Symfony (PHP), algunos raíles y algunos otros. Me encanta tener la capacidad de tener una o varias plantillas comunes y luego tener una sección específica de "contenido" donde van las cosas específicas de la página. No puedo entender cómo se hace esto con XSLT. En el caso de esta aplicación, tengo un valor disponible en el xml que respalda la página xslt, vamos a llamarlo ContentXSL, cuyo valor es el nombre del archivo xsl que quiero usar para la sección de contenido de la página. Sé que no es posible, pero sería bueno usar:
<xsl:call-template name="{$ContentXSL}" />
Luego, simplemente podría poner eso en la sección de contenido. Sin embargo, esto no es posible, así que en su lugar necesitaré una declaración de elección masiva que llame a la plantilla correcta en función de la variable ContentPage. Esto también significa que en mi archivo Layout.xsl I Tendría que incluir todos los documentos 40-50 x.l .. Creo que los gastos generales serían bastante grandes, pero no estoy seguro de eso. ¿Es razonable hacer esto si el sitio recibe mucho tráfico?
¿Cuáles son otras formas comunes de hacer esto? Parece que la mayoría de los marcos modernos le permiten usar este patrón para decorar el contenido. En el caso de Symfony, funcionó muy bien y era bastante flexible (con ranuras y todo eso).
Sé que la otra solución potencial es tener 40 archivos independientes que tengan un marcado similar e incluir secciones especiales como el encabezado y el pie de página. Esto significa que si quiero cambiar la estructura general del diseño de mi sitio, tendría que editar todas las páginas 40-50 (muy molesto).
Actualización - Más Explicación
Quiero seguir explicando esto porque tengo ciertos requisitos que requerirían una considerable ingeniería para cambiar. En primer lugar, el backend me va a pasar algo de XML que me permitirá saber si hay args de consulta en la URL del sitio web. Además, me pasará los datos que necesito para construir mi página (datos en el forma de datos comerciales, sin html ni nada de eso). Los datos son similares a esto:
<xml>
<section>Blogs</section>
<page>showAll</section>
<data>
<blogs>
<blog>
<author>somebody</author>
<title></title>
<content>..</content>
</blog>
</blog>..</blog>
</blogs>
</data>
</xml>
Ahora lo que quiero es tener una plantilla de página como esta:
<xsl:stylesheet version=''1.0'' xmlns:xsl=''http://www.w3.org/1999/XSL/Transform'' xmlns:msxsl=''urn:schemas-microsoft-com:xslt''>
<xsl:output omit-xml-declaration=''yes'' method=''html'' media-type=''text/html'' indent=''yes'' />
<xsl:include href="Header.xsl"/>
<xsl:include href="Nav.xsl"/>
<xsl:template name=''MainLayout'' match=''*''>
<html>
<head>
<title></title>
</head>
<body>
<div id="header"><xsl:call-template name="Header" /></div>
<div id="nav"><xsl:call-template name="Nav" /></div>
<div id="content">
[here is where i want to use the xsl from {/xml/section}/{/xml/page}.xsl]
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Ahora, para el contenido de esta página, tendría el siguiente archivo: Blogs / showAll.xsl
<xsl:stylesheet version=''1.0'' xmlns:xsl=''http://www.w3.org/1999/XSL/Transform'' xmlns:msxsl=''urn:schemas-microsoft-com:xslt''>
<xsl:output omit-xml-declaration=''yes'' method=''html'' media-type=''text/html'' indent=''yes'' />
<xsl:template name=''Blogs_ShowAll''>
<div id="blogs-showAll">
..iterate over /xml/data/blogs converting to html
</div>
</xsl:template>
</xsl:stylesheet>
Las soluciones hasta ahora han sido buenas, pero solo una de ellas fue capaz de digerir completamente (la que menciona incluir todos los archivos xsl y usar una xsl: elegir para seleccionar la correcta). No estoy seguro de cómo aplicar el método FXSL al problema en cuestión. Tenga en cuenta que no me opondría al uso de un enfoque de tipo de malla de sitio que especifique las etiquetas html / body y todo eso en el elemento secundario y haga que reemplace lo que tengo en la sección del cuerpo del elemento secundario en el contenido del diseño (también, si hay una etiqueta de título en el niño que reemplaza la etiqueta del título en el diseño, cosas así).
<xsl:call-template name="{$ContentXSL}" />
Si bien esto es sintácticamente ilegal en todas las versiones de XSLT , el uso de plantillas XSLT como funciones de orden superior se ha implementado y utilizado en la biblioteca FXSL desde hace diez años .
Aquí hay una idea algo simplificada de cómo se puede lograr esto:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pFunction1">
<fun name="increment"/>
</xsl:param>
<xsl:param name="pFunction2">
<fun name="double"/>
</xsl:param>
<xsl:variable name="vFunIncrement" select=
"document('''')/*/xsl:param[@name=''pFunction1'']/*"/>
<xsl:variable name="vFunDouble" select=
"document('''')/*/xsl:param[@name=''pFunction2'']/*"/>
<xsl:variable name="vInput" select="."/>
<xsl:template match="/">
increment(<xsl:value-of select="$vInput"/>) = <xsl:text/>
<xsl:apply-templates select="$vFunIncrement">
<xsl:with-param name="parg1" select="$vInput"/>
</xsl:apply-templates>
double(<xsl:value-of select="$vInput"/>) = <xsl:text/>
<xsl:apply-templates select="$vFunDouble">
<xsl:with-param name="parg1" select="$vInput"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="fun[@name=''double'']">
<xsl:param name="parg1"/>
<xsl:value-of select="2*$parg1"/>
</xsl:template>
<xsl:template match="fun[@name=''increment'']">
<xsl:param name="parg1"/>
<xsl:value-of select="$parg1+1"/>
</xsl:template>
</xsl:stylesheet>
cuando esta transformación se aplica en el siguiente documento XML :
<num>2</num>
el resultado es :
increment(2) = 3
double(2) = 4
Nota :
Los elementos
<fun>
se pueden pasar externamente a la transformación a través de parámetros de nivel global. Esto significa que la transformación no sabe qué funciones se ejecutarán.Las funciones se simulan mediante plantillas que combinan elementos
fun
que tienen un valor específico para su atributo dename
.
En caso de que quiera leer y comprender FXSL, estos son los dos mejores materiales:
Además de la excelente respuesta de Dimitre que recomienda un método para implementar funciones de orden superior, también puede usar un método con páginas maestras y páginas secundarias combinadas con algún tipo de código, como este:
MasterContent.xml:
<title>Test for XSLT</title>
MasterLayout.xml:
<html>
<head>
<title></title>
</head>
<body>
<p>This is master page</p>
</body>
</html>
Master.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pMasterLayout" select="document(''MasterLayout.xml'')"/>
<xsl:param name="pMasterContent" select="document(''MasterContent.xml'')"/>
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:apply-templates select="$pMasterLayout/*"/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="title">
<xsl:copy>
<xsl:value-of select="$pMasterContent/title"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
ChildLayout:
<html>
<head>
<title></title>
</head>
<body>
<h1></h1>
</body>
</html>
Entonces, esta transformación ("Child.xsl"):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="Master.xsl"/>
<xsl:param name="pChildLayout" select="document(''ChildLayout.xml'')"/>
<xsl:param name="pChildContent" select="/"/>
<xsl:template match="body">
<xsl:copy>
<xsl:apply-templates select="$pChildLayout/html/body/*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<xsl:copy>
<xsl:value-of select="$pChildContent/header"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Con esta entrada ("ChildContent"):
<header>Child Content</header>
Salida:
<html>
<head>
<title>Test for XSLT</title>
</head>
<body>
<h1>Child Content</h1>
</body>
</html>
Nota :
Verifique un mejor ejemplo de vida en aranedabienesraices.com.ar Recomiendo usar @id
como anclajes para poblar el diseño con contenido (puede @id
con plantillas vacías). Este método no lo vincula con ningún proveedor IDE (con la noción de XSLT) para construir sus páginas de diseño.
El ejemplo de Dimitre es bueno ...
Aquí hay una manera de hacer esto también ... una pequeña solución fea pero el truco
primary.xsl
<xsl:variable name="ContentXSL" select="/your/xml/settings/@content" />
<!-- Reference templates -->
<xsl:include href="template1.xsl" />
<xsl:include href="template2.xsl" />
<xsl:include href="template3.xsl" />
<xsl:include href="template4.xsl" />
<xsl:template match="/">
<html>
<head>
<title>..</title>
</head>
</html>
<body>
<xsl:call-template name="getcontent" />
</body>
</xsl:template>
<xsl:template name="getcontent">
<xsl:choose>
<xsl:when test="$ContentXSL = ''template1''">
<xsl:apply-templates match="/your/xml/structure" mode="template1" />
</xsl:when>
<xsl:when test="$ContentXSL = ''template2''">
<xsl:apply-templates match="/your/xml/structure" mode="template2" />
</xsl:when>
<xsl:when test="$ContentXSL = ''template3''">
<xsl:apply-templates match="/your/xml/structure" mode="template3" />
</xsl:when>
<xsl:when test="$ContentXSL = ''template4''">
<xsl:apply-templates match="/your/xml/structure" mode="template4" />
</xsl:when>
<xsl:otherwise>
<!-- Default template? -->
<xsl:apply-templates match="/your/xml/structure" mode="template1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
template1.xsl
<xsl:template match="/your/xml/structure" mode="template1">
Template 1<br />
</xsl:template>
template2.xsl
<xsl:template match="/your/xml/structure" mode="template2">
Template 2<br />
</xsl:template>
template3.xsl
<xsl:template match="/your/xml/structure" mode="template3">
Template 3<br />
</xsl:template>
template4.xsl
<xsl:template match="/your/xml/structure" mode="template4">
Template 4<br />
</xsl:template>
El OP ha proporcionado detalles adicionales de su problema y esta respuesta proporciona la solución adicional que ahora se solicita.
I. La idea:
Esta transformación :
<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:template match="/">
<html>
<xsl:apply-templates select="*/page"/>
</html>
</xsl:template>
<xsl:template match="page[. = ''showAll'']">
<!-- Transform all data to html -->
<xsl:apply-templates select="../*/blogs" mode="showAll"/>
</xsl:template>
<xsl:template match="page[. = ''showBrief'']">
<!-- Transform the data to Summary html -->
<xsl:apply-templates select="../*/blogs" mode="showBrief"/>
</xsl:template>
<xsl:template match="blogs" mode="showAll">
<h1>All Blogs: </h1>
<table border="1">
<xsl:apply-templates mode="showAll"/>
</table>
</xsl:template>
<xsl:template match="blog" mode="showAll">
<tr>
<td>Blog of <xsl:value-of select="author"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
<tr>
<td colspan="2"><xsl:apply-templates select="content/node()" mode="showAll"/></td>
</tr>
<xsl:if test="not(position()=last())">
<tr><td colspan="2"> </td></tr>
</xsl:if>
</xsl:template>
<xsl:template match="blogs" mode="showBrief">
<h1>Blogs Summary: </h1>
<table border="1">
<xsl:apply-templates mode="showBrief"/>
</table>
</xsl:template>
<xsl:template match="blog" mode="showBrief">
<tr>
<td>
<xsl:value-of select="concat(author, '': '', title)"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
cuando se aplica en este documento XML (basado en el texto XML provisto, pero haciéndolo bien formado y más sustancial):
<xml>
<section>Blogs</section>
<page>showAll</page>
<data>
<blogs>
<blog>
<author>John Smith</author>
<title>All about golden fish</title>
<content>
Here I publish my latest achievements
in raising golden fish.
</content>
</blog>
<blog>
<author>Mary Jones</author>
<title>Knitting, Knitting, Knitting</title>
<content>
How to knit a sharf.
</content>
</blog>
</blogs>
</data>
</xml>
produce el tipo de salida deseado "show-all" :
<html>
<h1>All Blogs: </h1>
<table border="1">
<tr>
<td>Blog of John Smith</td>
<td>All about golden fish</td>
</tr>
<tr>
<td colspan="2">
Here I publish my latest achievements
in raising golden fish.
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td>Blog of Mary Jones</td>
<td>Knitting, Knitting, Knitting</td>
</tr>
<tr>
<td colspan="2">
How to knit a sharf.
</td>
</tr>
</table>
</html>
Ahora cambiamos el documento XML y reemplazamos el elemento de page
con este :
<page>showBrief</page>
Cuando se aplica la misma transformación en el documento XML actualizado, ahora produce el resultado de resumen deseado :
<html>
<h1>Blogs Summary: </h1>
<table border="1">
<tr>
<td>John Smith: All about golden fish</td>
</tr>
<tr>
<td>Mary Jones: Knitting, Knitting, Knitting</td>
</tr>
</table>
</html>
II. El siguiente paso
En la práctica, todas las plantillas en un modo determinado estarán en su archivo xsl separado y serán importadas por la hoja de estilos primaria:
La transformación (hoja de estilo primaria) se convierte así :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="showAll.xsl"/>
<xsl:import href="showBrief.xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<xsl:apply-templates select="*/page"/>
</html>
</xsl:template>
</xsl:stylesheet>
Nota :
La transformación no sabe de antemano qué plantillas se aplicarán : la transformación está completamente dirigida a los datos.
Las plantillas que no existen ahora se pueden escribir en el futuro y se aplicarán sin la necesidad de cambiar la hoja de estilos primaria.
No hay lógica condicional ,
<xsl:choose>
instrucciones, etc. Este es el verdadero poder de las plantillas xsl en acción .Esta transformación se basa en la misma idea en la que se basa FXSL .