Fusionar dos xpathdocumentos utilizando xmlcompiledTransform
-
23-09-2019 - |
Pregunta
No puedo ser la primera persona en hacer esto, parece que sería una práctica tan común fusionar dos documentos usando XSLT. Sin embargo, parece que no puedo encontrar un solo ejemplo en el Ol 'Interweb.
Tengo dos documentos XML que se están recuperando como cadenas de XML de SQL Server. Quiero usar XslCompiledTransform
para fusionar los dos documentos. Yo sé eso XslCompiledTransform
apaga el XSL document()
función de forma predeterminada. He encendido eso en usar XsltSettings
Cuando creo mi XslCompiledTransform
objeto.
Entiendo cómo "agregar" el segundo documento a la transformación es usar un XsltArgumentList
y usa el AddParam()
método y agregar un XPathNavigator
objeto:
XsltArgumentList xsltArgs = new XsltArgumentList();
xsltArgs.AddParam(
(string)e.UserState + "s", "http://www.myuri.com/tabledata",
dataXmlDoc.CreateNavigator()
);
Sin embargo, cualquier intento de acceder al documento que se agregue resulta en un error o no se devuelve nada. - C#:
XslCompiledTransform fieldToXhtmlTransform = new XslCompiledTransform(true);
try
{
UriBuilder xsltUri = new UriBuilder(
Request.Url.Scheme, Request.Url.Host,
Request.Url.Port, this.ResolveUrl("Transforms/address1.xslt")
);
XmlSecureResolver resolver = new XmlSecureResolver(
new XmlUrlResolver(), new PermissionSet(PermissionState.Unrestricted)
);
fieldToXhtmlTransform.Load(
xsltUri.ToString(), new XsltSettings(true, false), resolver
);
}
catch
{
//TODO: do something useful here.
}
XPathDocument fieldSchemaXmlDoc = null;
using (MemoryStream fieldMemoryStream = new MemoryStream(
Encoding.UTF8.GetBytes(e.Result.TableMetaDataXml)
))
{
fieldSchemaXmlDoc = new XPathDocument(fieldMemoryStream);
}
XPathDocument dataXmlDoc = null;
using (MemoryStream dataMemoryStream = new MemoryStream(
Encoding.UTF8.GetBytes(e.Result.DataXml)
))
{
dataXmlDoc = new XPathDocument(dataMemoryStream);
}
StringBuilder output = new StringBuilder();
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
writerSettings.Encoding = Encoding.UTF8;
XsltArgumentList xsltArgs = new XsltArgumentList();
xsltArgs.AddParam(
(string)e.UserState + "s", "http://www.myuri.com/tabledata",
dataXmlDoc.CreateNavigator()
);
XmlWriter transformedDataWriter = XmlWriter.Create(output, writerSettings);
fieldToXhtmlTransform.Transform(
fieldSchemaXmlDoc, xsltArgs, transformedDataWriter
);
XSLT: solo accede al documento agregado, no el documento cargado con la transformación.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:hlsschema="http://www.myuri.com/tableschema"
xmlns:hlsdata="http://www.myuri.com/tabledata"
exclude-result-prefixes="msxsl hlsschema hlsdata xsl"
>
<xsl:output method="html" indent="yes"/>
<p>
<xsl:template match="hlsdata:Address1s">
<xsl:for-each select="hlsdata:Address1">
<p>
<xsl:value-of select="hlsdata:dr_id"/>
</p>
</xsl:for-each>
</xsl:template>
</p>
</xsl:stylesheet>
XML
<hlsdata:Address1s
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:hlsdata="http://www.myuri.com/tabledata"
>
<hlsdata:Address1>
<hlsdata:dr_id>12345678</hlsdata:dr_id>
</hlsdata:Address1>
</hlsdata:Address1s>
Sé que me estoy perdiendo algo obvio, pero es más que frustrante. Sé que el documento se agrega como parámetro, pero no puedo encontrar un ejemplo de cómo acceder a un documento cargado como parámetro.
Cualquier ayuda sería muy apreciada. Tenga en cuenta que el código anterior es un trabajo en progreso y es entre dos de los cientos de intentos para que funcione, por lo que si algo se ve un poco extraño, probablemente sea porque es entre intentos.
Solución
Debe definir un parámetro en su hoja de estilo y luego usar ese parámetro. Aquí hay un ejemplo simple, la hoja de estilo se ve de la siguiente manera:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:docs="http://example.com/2010/docs"
exclude-result-prefixes="docs"
>
<xsl:param name="docs:doc1" select="/.."/>
<xsl:template match="/">
<xsl:apply-templates select="$docs:doc1/node()"/>
</xsl:template>
<xsl:template match="root">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="foo">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
</xsl:stylesheet>
El código C# se ve de la siguiente manera:
string xml = "<root><foo>1</foo><foo>2</foo></root>";
XPathDocument doc = new XPathDocument(new StringReader(xml));
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load(@"..\..\XSLTFile1.xslt");
XsltArgumentList xsltArgs = new XsltArgumentList();
xsltArgs.AddParam("doc1", "http://example.com/2010/docs", doc.CreateNavigator());
proc.Transform(XmlReader.Create(new StringReader("<dummy/>")), xsltArgs, Console.Out);
Esta es una aplicación de consola que, por simplicidad, escribe en consola.
Ese ejemplo escribe <ul><li>1</li><li>2</li></ul>
Entonces el parámetro de entrada ha sido procesado.
Eso debería mostrarle cómo pasar un parámetro que XSLCompiledTransform ve como un conjunto de nodo que puede procesar con XSLT.
En cuanto a escribir una hoja de estilo que fusione dos documentos, publique dos muestras de entrada y la muestra de resultados correspondiente que desea crear si tiene problemas para escribir ese XSLT.