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.

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top