我有一个XML文档,内容与
类似<?xml version="1.0" encoding="UTF-8"?>
<Mod>
<Input1>
<Name>BackInput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Input1>
<Input2>
<Name>NeutralInput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Input2>
<Input3>
<Name>LightingInput</Name>
<Transform>
<Subsystem>Lighting</Subsystem>
</Transform>
</Input3>
<Output1>
<Name>BackOutput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Output1>
<Output2>
<Name>NeutralOutput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Output2>
<Output3>
<Name>LightingOutput</Name>
<Transform>
<Subsystem>Lighting</Subsystem>
</Transform>
</Output3>
<VariableData>
<Threshold name="LightingMax">
<Component>Lighting</Component>
</Threshold>
</VariableData>
</Mod>
我想获得唯一的子系统,以及所有唯一的前面的Name文本。按子系统排序,最后按名称排序。预期输出为
Lighting
LightingInput
LightingOutput
Transmission
BackInput
BackOutput
DriveInput
DriveOutput
NeutralInput
NeutralOutput
这是模拟数据。我似乎无法理解如何只输出唯一的数据项。
这是我现在使用的XSLT。请随意评论XSLT的任何方面,因为这是我第一次使用它。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="newline" select="' '"/>
<xsl:variable name="tab" select="'	'"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="//Subsystem|//Component">
<xsl:sort select="."/>
<xsl:sort select="../@name"/>
<xsl:sort select="../preceding-sibling::Name"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="//Subsystem|//Component">
<xsl:value-of select="concat($newline, .)"/>
<xsl:if test="../preceding-sibling::Name">
<xsl:value-of select="concat($newline, $tab, ../preceding-sibling::Name)"/>
</xsl:if>
<xsl:if test="../@name">
<xsl:value-of select="concat($newline, $tab, ../@name)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
当上面的XSLT应用于XML时的输出(注意,我在使用它时在第一行得到一个换行符,它似乎是因为我的XSLT但是如果我移动第一个xsl:value-of
我不喜欢#39;得到我期待的输出
<newline>
Lighting
LightingInput
Lighting
LightingOutput
Lighting
LightingMax
Transmission
BackInput
Transmission
BackOutput
Transmission
NeutralInput
Transmission
NeutralOutput
答案 0 :(得分:1)
随意评论XSLT的任何方面,因为这是第一个 我正在使用它。
以下是对现有样式表的一些评论...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="newline" select="' '"/>
<xsl:variable name="tab" select="'	'"/>
<xsl:template match="/">
<!--When your output method is text, you don't usually need to use xsl:copy.
Also, using xsl:copy when the context is the document node doesn't do anything
helpful.-->
<xsl:copy>
<xsl:apply-templates select="//Subsystem|//Component">
<xsl:sort select="."/>
<xsl:sort select="../@name"/>
<xsl:sort select="../preceding-sibling::Name"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!--You don't need the "//" in the match pattern. Just use "Subsystem|Component".
See https://www.w3.org/TR/xslt-10/#patterns for more info.-->
<xsl:template match="//Subsystem|//Component">
<!--This outputs a newline for every Subsystem or Component. Instead, just output
a newline if the position() is greater than 1. That way you won't have an extra
newline at the beginning of your output.-->
<xsl:value-of select="concat($newline, .)"/>
<xsl:if test="../preceding-sibling::Name">
<xsl:value-of select="concat($newline, $tab, ../preceding-sibling::Name)"/>
</xsl:if>
<xsl:if test="../@name">
<xsl:value-of select="concat($newline, $tab, ../@name)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
由于您使用的是XSLT 1.0,我要做的就是使用Muenchian Grouping。
首先按其值Subsystem
和Component
元素进行分组(示例中的第一个“level1”xsl:key)。您只是要输出此键中第一个节点的值。这将为您提供独特的清单。
然后将Name
元素和name
属性按Component
或Subsystem
的值(示例中的第二个“名称”xsl:键)进行分组。获取组件或子系统有点棘手,因为您选择了元素或属性,并且它们位于树中的不同级别。要做到这一点,我们首先需要将树(..
)返回到父级,然后将树(//
)返回到组件或子系统。
请花一些时间查看上面链接的Muenchian Grouping page;它将帮助您理解我的示例中的分组部分。
示例...
XML输入
<Mod>
<Input1>
<Name>BackInput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Input1>
<Input2>
<Name>NeutralInput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Input2>
<Input3>
<Name>LightingInput</Name>
<Transform>
<Subsystem>Lighting</Subsystem>
</Transform>
</Input3>
<Output1>
<Name>BackOutput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Output1>
<Output2>
<Name>NeutralOutput</Name>
<Transform>
<Subsystem>Transmission</Subsystem>
</Transform>
</Output2>
<Output3>
<Name>LightingOutput</Name>
<Transform>
<Subsystem>Lighting</Subsystem>
</Transform>
</Output3>
<VariableData>
<Threshold name="LightingMax">
<Component>Lighting</Component>
</Threshold>
</VariableData>
</Mod>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:key name="level1"
match="Subsystem|Component"
use="normalize-space()"/>
<xsl:key name="names"
match="Name|*[@name]/@name"
use="normalize-space(..//*[self::Subsystem or self::Component])"/>
<xsl:template match="/Mod">
<xsl:for-each
select=".//*[self::Subsystem or self::Component][
count(.|key('level1',normalize-space())[1])=1]">
<xsl:sort select="normalize-space()"/>
<xsl:if test="position() > 1">
<xsl:value-of select="'
'"/>
</xsl:if>
<xsl:value-of select="normalize-space()"/>
<xsl:for-each select="key('names',normalize-space())">
<xsl:sort select="normalize-space()"/>
<xsl:value-of select="concat('
	',normalize-space())"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
Lighting
LightingInput
LightingMax
LightingOutput
Transmission
BackInput
BackOutput
NeutralInput
NeutralOutput
答案 1 :(得分:0)
考虑Muenchian Grouping按XSLT 1.0中的特定值索引文档,并循环遍历相应的项目,例如祖父母名称:../../Name
:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:key name="subid" match="Subsystem" use="."/>
<xsl:template match ="/Mod">
<xsl:apply-templates select="descendant::Subsystem[generate-id() =
generate-id(key('subid', .)[1])]">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match ="Subsystem">
<xsl:value-of select="."/><xsl:text>
</xsl:text><!-- LINE BREAK -->
<xsl:for-each select="key('subid', .)">
<xsl:sort select="../../Name"/>
<xsl:text>	</xsl:text> <!-- TAB -->
<xsl:value-of select="../../Name"/>
<xsl:text>
</xsl:text> <!-- LINE BREAK -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>