#asp.net #xml #xslt #xmldatasource
#asp.net #xml — файл #xslt #xmldatasource — источник данных #xml #xmldatasource
Вопрос:
У меня все работает (спасибо empo), кроме столбца ctrlname. Я недостаточно хорошо знаю синтаксис. Что я пытаюсь сделать, так это использовать xslt для сортировки xml в gridview по имени столбца. Все работает, кроме столбца ctrlname. Как мне передать атрибут в XSLT? Я пробовал: @name, Data/@name, Data[@name], ctrlname. Ничего не работает.
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>
Ввод 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>
Комментарии:
1. Хороший вопрос, 1. Смотрите мой ответ для более мощного и универсального решения, которое короче и позволяет правильно сортировать даже в случае, когда есть атрибут и дочерний элемент с одинаковым именем. 🙂
2. Я также предоставил подробное объяснение.
Ответ №1:
Принятый в настоящее время ответ имеет один недостаток: всякий раз, когда существует атрибут data
с тем же именем, что и дочерний элемент data
, сортировка всегда будет выполняться с использованием в качестве ключей значений атрибута. Кроме того, это слишком длинно.
Это решение решает проблему (и короче), позволяя указать, должна ли сортировка производиться по имени атрибута или по имени элемента:
<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>
При применении к этому XML-документу (на основе предоставленного, но сделанного немного более интересным):
<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>
получен правильный результат (отсортированный по name
атрибуту):
<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>
Теперь замените <xsl:param name="sortby" select="'attrib!name'"/>
на:
<xsl:param name="sortby" select="'elem!name'"/>
и снова применить преобразование к тому же XML-документу. На этот раз мы получаем результат, правильно отсортированный по значениям дочернего элемента 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>
Объяснение:
-
Чтобы отличить, хотим ли мы выполнить сортировку по дочернему элементу или по атрибуту, мы используем соглашение, которое
elem!someName
означает, что сортировка должна производиться по значениям дочернего элемента с именемsomeName
. Аналогично,attrib!someName
означает, что сортировка должна производиться по значениям атрибута с именемsomeName
. -
<xsl:sort>
Структура изменена соответствующим образом, чтобы правильно выбрать в качестве ключа либо атрибут, либо дочерний элемент. Двусмысленность не допускается, потому что начальная подстрокаsortby
параметра теперь однозначно определяет, должен ли ключ быть атрибутом или дочерним элементом.
Ответ №2:
Да, извините, не заметил, что вы хотели также сортировать по атрибутам. Обратите также внимание, что вы изменили синтаксис xsl:param
, и это неверно таким образом. Очень важно, чтобы вы сохраняли одинарные кавычки внутри двойных. Вот окончательный шаблон:
<?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>
Комментарии:
1. Спасибо! Я не знаю, является ли XslArgumentList причиной, по которой мне не нужны значения select для xsl: params. Но в моем текущем коде у меня нет значений select, и это работает просто отлично. Но я изменю свой код, чтобы он соответствовал вашему коду. Поскольку ваш код правильный.
Ответ №3:
Хорошо, я думаю, это должно сработать для вас, позволяя вам указывать имена атрибутов или элементов в параметре $ 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>
(вы бы просто передали «name» в качестве значения параметра $ sortby)
Проблема заключалась в том, что при выборе узла значения сортировки были выбраны только соответствующие элементы ( *
matches elements only только).
Комментарии:
1. Я хотел бы также отметить вас в качестве ответа. Кто-то 1 этому парню! Спасибо, Тао.