我正在尝试使用XSL对XML文件进行排序。我对XSL很陌生,并编写了一个.Net应用程序,将XSL应用于XML并将其保存到新文件中。这很好用。 XML的简化版本看起来像这样(精明的读者会注意到它是一个Management Studio项目文件):
<?xml version="1.0"?>
<SqlWorkbenchSqlProject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Name="PMISQL">
<Items>
<LogicalFolder Name="Connections" Type="2" Sorted="true">
<Items>
<ConnectionNode Name="cerberus:XPOOLE\barney.russ">
<Created>2013-06-28T15:50:27.919788+01:00</Created>
<Type>SQL</Type>
<Server>cerberus</Server>
<UserName />
<Authentication>Windows Authentication</Authentication>
<InitialDB>master</InitialDB>
<LoginTimeout>15</LoginTimeout>
<ExecutionTimeout>0</ExecutionTimeout>
<ConnectionProtocol>NotSpecified</ConnectionProtocol>
<ApplicationName>Microsoft SQL Server Management Studio - Query</ApplicationName>
</ConnectionNode>
</Items>
</LogicalFolder>
<LogicalFolder Name="Queries" Type="0" Sorted="true">
<Items>
<FileNode Name="PMI193_Documents.sql">
<AssociatedConnectionMoniker>8c91a03d-f9b4-46c0-a305-b5dcc79ff907:tyro:True</AssociatedConnectionMoniker>
<AssociatedConnSrvName>tyro</AssociatedConnSrvName>
<AssociatedConnUserName />
<FullPath>PMI193_Documents.sql</FullPath>
</FileNode>
<FileNode Name="PMI002_EventTypes.sql">
<AssociatedConnectionMoniker>8c91a03d-f9b4-46c0-a305-b5dcc79ff907:cerberus:True</AssociatedConnectionMoniker>
<AssociatedConnSrvName>cerberus</AssociatedConnSrvName>
<AssociatedConnUserName />
<FullPath>PMI002_EventTypes.sql</FullPath>
</FileNode>
<FileNode Name="PMI079a_DementiaScreeningDetail.sql">
<AssociatedConnectionMoniker>8c91a03d-f9b4-46c0-a305-b5dcc79ff907:tyro:True</AssociatedConnectionMoniker>
<AssociatedConnSrvName>tyro</AssociatedConnSrvName>
<AssociatedConnUserName />
<FullPath>PMI079a_DementiaScreeningDetail.sql</FullPath>
</FileNode>
</Items>
</LogicalFolder>
<LogicalFolder Name="Miscellaneous" Type="3" Sorted="true">
<Items />
</LogicalFolder>
</Items>
<SccProjectName>$/DataWarehouse/Dev/Reports</SccProjectName>
<SccAuxPath />
<SccLocalPath>..</SccLocalPath>
<SccProvider>MSSCCI:Team Foundation Server MSSCCI Provider</SccProvider>
</SqlWorkbenchSqlProject>
您会注意到有几个LogicalFolder部分。我只想对属性Name =&#34; Queries&#34;我希望它按子元素Items / FileNode / FullPath排序。
我已经使用了一些XSL,它是身份XSL并对其进行了扩展。它会重现原始文件,但不会对我想要的部分进行排序(实际上它似乎没有排序)。我创建的XSL看起来像这样:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/ | @* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/SqlWorkbenchSqlPro/Items/LogicalFolder/Items">
<xsl:apply-templates select=".">
<xsl:sort select="FullPath"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
我不知道如何指定我只对排序部分/ SqlWorkbenchSqlPro / Items / LogicalFolder / Items感兴趣,其中Name =&#34; Queries&#34;,如何指定哪个级别要排序的元素,以及如何指定用于对项目进行排序的元素。真的,我在XSL上并不是很擅长,因为我几个小时前才开始看它。
任何帮助非常感谢。我很头疼。
答案 0 :(得分:0)
您在身份模板上构建的事实是一个良好的开端,所以您不远处。您遇到的第一个问题是您的模板引用SqlWorkbenchSqlPro
,但在您的XML中它是SqlWorkbenchSqlProject
,因此不匹配任何内容。
但是还没有去纠正它,因为如果你单独做到这一点,你的模板就会卡在一个循环中。使用<xsl:apply-templates select=".">
只会选择相同的匹配模板。你应该在这里<xsl:apply-templates select="FileNode" />
,或只是<xsl:apply-templates />
但是要回答您的主要问题,您可以在方括号中添加条件以定位您想要的节点
<xsl:template match="LogicalFolder[@Name='Queries']/Items">
请注意,此处无需指定节点的完整路径。
试试这个XSLT
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="LogicalFolder[@Name='Queries']/Items">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort select="FullPath"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意在xsl:copy
模板中使用Items
,以便在选择和排序其子节点之前复制现有的Items
元素。
答案 1 :(得分:0)
如何指定我只对排序
部分感兴趣LogicalFolder/Items
Name="Queries"
这很容易。制作模板,使其仅匹配此特定类型的节点。
<xsl:template match="LogicalFolder[@Name = 'Queries']/Items">
<xsl:copy>
<xsl:apply-templates select="*">
<xsl:sort select="FullPath" data-type="text" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
这会复制<Items>
元素。之后,您不再需要将模板应用于.
(当前节点,即<Items>
),而是*
(所有子元素,即<FileNode>
)
如何指定要排序的元素级别,
这也很容易。订购适用于所选节点。在上面的例子中,选择了所有子元素。这意味着排序仅限于LogicalFolder/Items
下的元素的顶级。
假设可以嵌套<Items>
并且您想要递归排序,您需要做的就是更改模板以应用于{{>所有节点<Items>
内LogicalFolder[@Name = 'Queries']
1}}通过更改match
表达式,如下所示:
<xsl:template match="Items[ancestor::LogicalFolder[@Name = 'Queries']]">
不需要进行其他更改,XSLT处理器会为您执行递归操作。 (<xsl:apply-templates>
是递归步骤。)
以及如何指定用于对项目进行排序的元素
<xsl:sort>
中的select表达式始终与正在排序的节点相关。在上面,
<xsl:apply-templates select="*">
选择一堆<FileNode>
元素,这意味着
<xsl:sort select="FullPath" data-type="text" />
是对的。 (data-type
添加了,因为这是一种很好的做法,不是因为它是绝对必要的。text
是默认的。)