Xml 如何在VB.NET(VS2008)中使用XSLT指定自定义属性排序顺序
我有这样一个模式: XML:Xml 如何在VB.NET(VS2008)中使用XSLT指定自定义属性排序顺序,xml,vb.net,xslt,visual-studio-2008,Xml,Vb.net,Xslt,Visual Studio 2008,我有这样一个模式: XML: 我需要它在每次交付中对产品代码进行排序,因此输出为: XML: 产品代码为字母或空白。以下规则适用: 产品代码R应首先出现 产品代码G应最后出现 还有别的事吗 我以前从未在愤怒中使用过XSLT,而且我已经很久没有使用任何VB.NET了,所以为了让某些东西工作起来,我提出了以下建议 Module Module1 Sub Main() ' The document Dim document As String =
我需要它在每次交付中对产品代码进行排序,因此输出为:
XML:
产品代码为字母或空白。以下规则适用:
Module Module1
Sub Main()
' The document
Dim document As String = "<Shipment> <Destination City='New York'> <Delivery> <Product ProductCode='B' ProductType='THI'></Product> <Product ProductCode='U' ProductType='SIS'></Product> <Product ProductCode='R' ProductType='JUS'></Product> <Product ProductCode='G' ProductType='TMA'></Product> <Product ProductCode='E' ProductType='DEU'></Product> <Product ProductCode='R' ProductType='POK'></Product> </Delivery> </Destination> <Destination City='London'> <Delivery> <Product ProductCode='C' ProductType='MAK'></Product> <Product ProductCode='H' ProductType='ESN'></Product> <Product ProductCode='E' ProductType='OSE'></Product> <Product ProductCode='R' ProductType='NSE'></Product> <Product ProductCode='R' ProductType='ATA'></Product> <Product ProductCode='Y' ProductType='LLL'></Product> </Delivery> </Destination> <Destination City='Paris'> <Delivery> <Product ProductCode='B' ProductType='WHO'></Product> <Product ProductCode='A' ProductType='WAT'></Product> <Product ProductCode='G' ProductType='CHE'></Product> <Product ProductCode='E' ProductType='STH'></Product> <Product ProductCode='L' ProductType='WAT'></Product> <Product ProductCode='S' ProductType='CHM'></Product> </Delivery> </Destination> <Destination City='Munich'> <Delivery> <Product ProductCode='Q' ProductType='ENN'></Product> <Product ProductCode='U' ProductType='THE'></Product> <Product ProductCode='I' ProductType='SHA'></Product> <Product ProductCode='C' ProductType='DOW'></Product> <Product ProductCode='H' ProductType='KNO'></Product> <Product ProductCode='E' ProductType='WSS'></Product> </Delivery> </Destination> </Shipment> "
' Load it
Dim xDoc As XmlDocument = New XmlDocument()
xDoc.LoadXml(DirtyHack(document))
' Required for string output
Dim sb As StringBuilder = New StringBuilder()
Dim writer As XmlWriter = XmlWriter.Create(sb)
' Do the transformation
Dim tranny As XslCompiledTransform = New XslCompiledTransform()
tranny.Load("c:\sandbox\MassageXML\Autobots.xslt")
tranny.Transform(xDoc, writer)
' See what mess we've made
Debug.WriteLine(sb.ToString)
End Sub
Function DirtyHack(ByVal inputString As String) As String
Dim dict = New Dictionary(Of String, String)
dict.Add("ProductCode='", "SortOrder='2' ProductCode='")
dict.Add("SortOrder='2' ProductCode='R'", "SortOrder='1' ProductCode='R'")
dict.Add("SortOrder='2' ProductCode='G'", "SortOrder='3' ProductCode='G'")
For Each kvp As KeyValuePair(Of String, String) In dict
inputString = inputString.Replace(kvp.Key, kvp.Value)
Next
Return inputString
End Function
End Module
模块1
副标题()
"文件,
将文档设置为字符串=“”
“加载它
Dim xDoc As XmlDocument=新XmlDocument()
LoadXml(DirtyHack(文档))
'对于字符串输出是必需的
将某人调整为StringBuilder=新建StringBuilder()
Dim writer As XmlWriter=XmlWriter.Create(sb)
"转型"
Dim tranny As XslCompiledTransform=新XslCompiledTransform()
Load(“c:\sandbox\MassageXML\Autobots.xslt”)
Transform(xDoc,编写器)
“看看我们搞得多糟
调试写线(某人写字符串)
端接头
函数DirtyHack(ByVal inputString作为String)作为String
Dim dict=新字典(字符串、字符串)
dict.Add(“ProductCode=”,“SortOrder='2'ProductCode=”)
dict.Add(“SortOrder='2'产品代码='R'”,“SortOrder='1'产品代码='R'”)
dict.Add(“SortOrder='2'产品代码='G'”,“SortOrder='3'产品代码='G'”)
对于dict中的每个kvp作为KeyValuePair(字符串、字符串)的
inputString=inputString.Replace(kvp.Key,kvp.Value)
下一个
返回输入字符串
端函数
端模块
本质上,我在运行中添加了另一个属性,按此排序,然后删除它,但我确信一定有更干净的方法。有什么想法吗
这是迄今为止的XSLT脚本:
<?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:output method="xml" indent="yes"/>
<xsl:template match="@SortOrder" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Delivery">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="@SortOrder" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我的建议是,它将产品代码到数字排序值的映射定义为一个参数,并在
xsl:sort
中选择该参数,唯一的缺点是,在XSLT 1.0中,您需要exsl:node set
或msxsl:node set
将参数所在的结果树片段转换为节点集,以便能够使用它,如图所示:
<?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"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="msxsl exsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="sort-map-rtf">
<map pc="R" sort="1"/>
<map pc="G" sort="3"/>
<map pc="*" sort="2"/>
</xsl:param>
<xsl:variable name="sort-map" select="exsl:node-set($sort-map-rtf)/map"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Delivery">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="($sort-map[@pc = current()/@ProductCode] | $sort-map[@pc = '*'])[1]/@sort" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在线示例位于。能否将XML输入作为代码片段发布?否则,很难推荐一些经过测试的代码,因为没有要测试的输入数据。我认为您应该能够在XSLT中定义排序顺序,而无需首先操作XML输入。非常好-谢谢。我将研究exsl:节点集
<?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:output method="xml" indent="yes"/>
<xsl:template match="@SortOrder" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Delivery">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="@SortOrder" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?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"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="msxsl exsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="sort-map-rtf">
<map pc="R" sort="1"/>
<map pc="G" sort="3"/>
<map pc="*" sort="2"/>
</xsl:param>
<xsl:variable name="sort-map" select="exsl:node-set($sort-map-rtf)/map"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Delivery">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="($sort-map[@pc = current()/@ProductCode] | $sort-map[@pc = '*'])[1]/@sort" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>