Como passo um atributo xml para o parâmetro xslt?
-
15-11-2019 - |
Pergunta
Fiz tudo funcionar (obrigado empo), exceto a coluna ctrlname.Não conheço bem a sintaxe.O que estou tentando fazer é usar o xslt para classificar o xml no gridview pelo nome da coluna.Tudo está funcionando, exceto a coluna ctrlname.Como passo um atributo para o XSLT?Eu tentei:@nome, Dados/@nome, Dados[@nome], ctrlnome.Nada funciona.
XmlDataSource1.EnableCaching = False
Dim xslTrnsform As System.Xml.Xsl.XsltArgumentList = New System.Xml.Xsl.XsltArgumentList
xslTrnsform.AddParam("sortby", "", sortAttr)
xslTrnsform.AddParam("orderas", "", orderby)
XmlDataSource1.TransformArgumentList = xslTrnsform
XmlDataSource1.DataFile = "~/App_LocalResources/DST_Test.xml"
XmlDataSource1.XPath = "//data"
XmlDataSource1.TransformFile = xsltFileName
'XmlDataSource1.DataBind()
GridView1.DataSource = XmlDataSource1
GridView1.DataBind()
XSL
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:param name="sortby"></xsl:param>
<xsl:param name="orderas"></xsl:param>
<xsl:output method="xml" indent="yes"/>
<!--<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>-->
<xsl:template match="root">
<root>
<xsl:apply-templates select="data">
<xsl:sort select="*[name()=$sortby]" data-type="text" order="{$orderas}"/>
</xsl:apply-templates>
</root>
</xsl:template>
<xsl:template match="data">
<data>
<xsl:attribute name="ctrlname">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="value" />
</xsl:attribute>
<xsl:attribute name="comment">
<xsl:value-of select="comment" />
</xsl:attribute>
</data>
</xsl:template>
</xsl:stylesheet>
Entrada XML
<?xml version="1.0" encoding="utf-8" ?>
<root>
<data name="Test1.Text" xml:space="preserve">
<value>Please Pick Bare Pump</value>
<comment>Tab - Pump Configuration</comment>
</data>
<data name="Test2.Text" xml:space="preserve">
<value>Complete</value>
<comment>A07</comment>
</data>
<data name="Test3.Text" xml:space="preserve">
<value>Confirmed</value>
<comment>A01</comment>
</data>
</root>
Solução
Sim, sinto muito, não percebi que você também queria classificar por atributos.Observe também que você alterou a sintaxe de xsl:param
e não é correto dessa forma.É muito importante que você mantenha as aspas simples dentro das duplas.Aqui está o modelo final:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:param name="sortby" select="'value'"/>
<xsl:param name="orderas" select="'ascending'"/>
<xsl:output method="xml" indent="yes"/>
<!--<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>-->
<xsl:template match="root">
<root>
<xsl:apply-templates select="data">
<xsl:sort select="*[name()=$sortby]|@*[name()=$sortby]" data-type="text" order="{$orderas}"/>
</xsl:apply-templates>
</root>
</xsl:template>
<xsl:template match="data">
<data>
<xsl:attribute name="ctrlname">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="value" />
</xsl:attribute>
<xsl:attribute name="comment">
<xsl:value-of select="comment" />
</xsl:attribute>
</data>
</xsl:template>
</xsl:stylesheet>
Outras dicas
A resposta atualmente aceita tem uma falha:Sempre que houver um atributo de data
com o mesmo nome de um elemento filho de data
, a ordenação sempre será realizada utilizando como chaves os valores do atributo.Além disso, é muito longo.
Esta solução resolve o problema (e é mais curto) permitindo especificar se a classificação deve ser por nome de atributo ou por nome de elemento:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="sortby" select="'attrib!name'"/>
<xsl:param name="orderas" select="'ascending'"/>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="root">
<root>
<xsl:apply-templates select="data">
<xsl:sort select=
"*[name()=substring-after($sortby, 'elem!')]
|
@*[name()=substring-after($sortby, 'attrib!')]"
data-type="text" order="{$orderas}"/>
</xsl:apply-templates>
</root>
</xsl:template>
<xsl:template match="data">
<data ctrlname="{@name}" value="{value}"
comment="{comment}"/>
</xsl:template>
</xsl:stylesheet>
Quando aplicado neste documento XML (com base no fornecido, mas um pouco mais interessante):
<root>
<data name="Test3.Text" xml:space="preserve">
<value>Please Pick Bare Pump</value>
<comment>Tab - Pump Configuration</comment>
<name>X</name>
</data>
<data name="Test2.Text" xml:space="preserve">
<value>Complete</value>
<comment>A07</comment>
<name>Z</name>
</data>
<data name="Test1.Text" xml:space="preserve">
<value>Confirmed</value>
<comment>A01</comment>
<name>Y</name>
</data>
</root>
o resultado correto (classificado pelo name
atributo) é produzido:
<root>
<data ctrlname="Test1.Text" value="Confirmed" comment="A01"/>
<data ctrlname="Test2.Text" value="Complete" comment="A07"/>
<data ctrlname="Test3.Text" value="Please Pick Bare Pump" comment="Tab - Pump Configuration"/>
</root>
Agora, substitua o <xsl:param name="sortby" select="'attrib!name'"/>
com:
<xsl:param name="sortby" select="'elem!name'"/>
e aplique a transformação novamente no mesmo documento XML.Desta vez, obtemos o resultado classificado corretamente pelos valores do filho-elemento name
:
<root>
<data ctrlname="Test3.Text" value="Please Pick Bare Pump" comment="Tab - Pump Configuration"/>
<data ctrlname="Test1.Text" value="Confirmed" comment="A01"/>
<data ctrlname="Test2.Text" value="Complete" comment="A07"/>
</root>
Explicação:
Para distinguir se queremos ordenar por um elemento-filho ou por um atributo, usamos a convenção que
elem!someName
significa que a classificação deve ser pelos valores de um elemento filho chamadosomeName
.De forma similar,attrib!someName
significa que a classificação deve ser pelos valores de um atributo chamadosomeName
.O
<xsl:sort>
A instrução é modificada de acordo para selecionar como chave corretamente um atributo ou um elemento filho.Nenhuma ambigüidade é permitida, porque a substring inicial dosortby
O parâmetro agora identifica exclusivamente se a chave deve ser um atributo ou um elemento filho.
OK, acho que isso deve funcionar para você, permitindo especificar nomes de atributos ou elementos no parâmetro $sortby:
<xsl:template match="root">
<root>
<xsl:apply-templates select="data">
<xsl:sort select="*[name()=$sortby] | @*[name()=$sortby]" data-type="text" order="{$orderas}"/>
</xsl:apply-templates>
</root>
</xsl:template>
(você apenas passaria "nome" como o valor do parâmetro $ sortby)
O problema era que a seleção do nó do valor de classificação correspondia apenas aos elementos (*
corresponde apenas a elementos).