我有一些XML,其中包含记录FilePath
和FileName
的节点。我需要一个XSLT
才能将它们转换为FilePathAndName
的单个节点。 FilePath
值可以或可以不以'\'结尾。任何值都可以为空。如果FilePathAndName
值只是一个文件夹名称,则必须以'\'结尾。
将从C#应用程序调用转换,因此我认为我可以使用任何版本的XSLT。
我已经走了一段路,但是正在努力寻求完整的解决方案,包括考虑输入中可选的'\'值。
以下是一些示例输入XML:
<Task>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="folder1\sub-folder1" /> <!-- FilePath doesn't end in '\' -->
<Parameter ParameterName="FileName" ParameterValue="file1" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="folder2\sub-folder2\" /> <!-- FilePath ends in '\' -->
<Parameter ParameterName="FileName" ParameterValue="file2" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="" /> <!-- Empty FilePath -->
<Parameter ParameterName="FileName" ParameterValue="file3" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="folder4\sub-folder4" /> <!-- Empty FileName -->
<Parameter ParameterName="FileName" ParameterValue="" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="" /> <!-- Empty FilePath and FileName -->
<Parameter ParameterName="FileName" ParameterValue="" />
</Action>
<Action ActionName="GetRateData">
<!-- No FilePath Node -->
<Parameter ParameterName="FileName" ParameterValue="file5" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePath" ParameterValue="folder6\sub-folder6" />
<!-- No FileName Node -->
</Action>
<Action ActionName="GetRateData">
<!-- No FilePath or FileName Node -->
</Action>
</Task>
应转换为以下内容:
<Task>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder1\sub-folder1\file1" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder2\sub-folder2\file2" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="file3" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder4\sub-folder4\" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="file5" />
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder6\sub-folder6\"/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="" />
</Action>
</Task>
这是我尝试的解决方案:
<xsl:template match="Task">
<Task>
<xsl:for-each select="Action">
<Action>
<xsl:copy-of select="@ActionName"/>
<xsl:for-each select="Parameter">
<Parameter>
<xsl:choose>
<xsl:when test="@ParameterName = 'FilePath'">
<xsl:attribute name="ParameterName">
<xsl:text>FilePathAndName</xsl:text>
</xsl:attribute>
<xsl:attribute name="ParameterValue">
<xsl:value-of select="@ParameterValue" />\<xsl:value-of select="(../Parameter[@ParameterName='FileName'])[1]/@ParameterValue" /></xsl:attribute>
<!-- TODO: Don't include '\' if FilePath is empty. -->
<!-- TODO: What if FilePath is missing? -->
</xsl:when>
<xsl:when test="@ParameterName = 'FileName'">
<!-- FileName will be consumed above. -->
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="@ParameterName"/>
<xsl:copy-of select="@ParameterValue"/>
</xsl:otherwise>
</xsl:choose>
</Parameter>
</xsl:for-each>
</Action>
</xsl:for-each>
</Task>
</xsl:template>
</xsl:stylesheet>
产生以下内容(有关其余问题,请参见下面的XML注释):
<Task
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName"
ParameterValue="folder1\sub-folder1\file1"/> <!-- Correct -->
<Parameter/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName"
ParameterValue="folder2\sub-folder2\\file2"/> <!-- Wrong: Should not have \\ -->
<Parameter/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="\file3"/> <!-- Wrong: FilePathAndName should not start with \ -->
<Parameter/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder4\sub-folder4\"/> <!-- Correct -->
<Parameter/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="\"/> <!-- Wrong: FilePathAndName should not start with \ -->
<Parameter/>
</Action>
<Action ActionName="GetRateData"> <!-- Wrong: FilePathAndName is missing -->
<Parameter/>
</Action>
<Action ActionName="GetRateData">
<Parameter ParameterName="FilePathAndName" ParameterValue="folder6\sub-folder6\"/> <!-- Correct -->
</Action>
<Action ActionName="GetRateData"/> <!-- Correct -->
</Task>
答案 0 :(得分:3)
如果您可以使用XSLT 2.0,则可以这样做
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Action">
<xsl:copy>
<xsl:copy-of select="@*" />
<Parameter FileNameAndPath="{replace(Parameter[@ParameterName='FilePath']/@ParameterValue, '([^\\])$', '$1\\')}{Parameter[@ParameterName='FileName']/@ParameterValue}" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果最后一个字符还不是反斜杠(并且必须具有最后一个字符,否则它不会添加一个),它使用replace
将反斜杠附加到“ FilePath”。
请注意,我在这里使用属性值模板来进一步减少代码的大小,而不是使用xsl:attribute
在XSLT 1.0中,表达添加反斜杠的逻辑变得更加冗长
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Action">
<xsl:copy>
<xsl:copy-of select="@*" />
<Parameter>
<xsl:attribute name="FileNameAndPath">
<xsl:variable name="FilePath" select="Parameter[@ParameterName='FilePath']/@ParameterValue" />
<xsl:value-of select="$FilePath" />
<xsl:if test="$FilePath != '' and substring($FilePath, string-length($FilePath)) != '\'">\</xsl:if>
<xsl:value-of select="Parameter[@ParameterName='FileName']/@ParameterValue" />
</xsl:attribute>
</Parameter>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>