在XSL转换中,有两件事我无法弄清楚。 在源XML
中<Network>
<Hosts>
<Host modelId="1" name="H1">
<LinPorts>
<LinPort name="Port3" speed="100" parent="H1"/>
</LinPorts>
<CanPorts/>
<EthernetPorts>
<EthernetPort name="Port1" speed="100" parent="H1"/>
<EthernetPort name="Port2" speed="100" parent="H1"/>
</EthernetPorts>
</Host>
<Host modelId="1" name="H2">
<CanPorts>
<CanPort name="Port2" speed="100" parent="H2"/>
</CanPorts>
<EthernetPorts>
<EthernetPort name="Port1" speed="100" parent="H3"/>
</EthernetPorts>
</Host>
<Host modelId="1" name="lin">
<LinPorts>
<LinPort name="Port1" speed="10" parent="lin"/>
<LinPort name="Port2" speed="100" parent="H2"/>
<LinPort name="Port3" speed="100" parent="lin"/>
</LinPorts>
</Host>
</Hosts>
<DataFrames>
<DataFrame bitSize="21" name="greasd" offset="0.021" period="0.021" prio="0">
<Path name="greasd-S5" parent="greasd">
<Node name="H1" sequenceNumber="1" parent="greasd-S5"/>
<Node name="S5" sequenceNumber="2" parent="greasd-S5"/>
</Path>
</DataFrame>
<DataFrame bitSize="23" name="hytdsg" offset="0.423" period="0.423" prio="0">
<Path name="hytdsg-H1" parent="hytdsg">
<Node name="H2" sequenceNumber="1" parent="hytdsg-H1"/>
<Node name="S5" sequenceNumber="2" parent="hytdsg-H1"/>
<Node name="H1" sequenceNumber="3" parent="hytdsg-H1"/>
</Path>
</DataFrame>
</DataFrames>
</Network>
某些子节点放置不正确。我正在使用@parent属性来正确放置它们。使用下面的XSLT可以很好地工作。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<!-- Copy all nodes (that do not get a better match) as they are -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Host">
<xsl:variable name="hostname" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<LinPorts>
<xsl:apply-templates select="//LinPorts/LinPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</LinPorts>
<CanPorts>
<xsl:apply-templates select="//CanPorts/CanPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</CanPorts>
<EthernetPorts>
<xsl:apply-templates
select="//EthernetPorts/EthernetPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</EthernetPorts>
</xsl:copy>
</xsl:template>
<xsl:template match="DataFrame">
<xsl:variable name="framename" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="//Path[@parent=$framename]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="Path">
<xsl:variable name="pathname" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="//Node[@parent=$pathname]">
<xsl:sort select="@sequenceNumber" data-type="text" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- Do not save attributes parent and ID for child elements -->
<xsl:template match="CanPort|LinPort|EthernetPort|Node">
<xsl:copy>
<xsl:apply-templates select="@*[not(name()='parent') and not(name()='id')]">
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
对于第1点,您可以在创建LinPort,CanPorts和EthernetPorts元素之前使用xsl:if
检查LinPort,CanPort和EthernetPort的计数
对于2,添加另一个匹配@parent
的模板并且不执行任何操作:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Host">
<xsl:variable name="hostname" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="count(//LinPorts/LinPort[@parent=$hostname]) != 0">
<LinPorts>
<xsl:apply-templates select="//LinPorts/LinPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</LinPorts>
</xsl:if>
<xsl:if test="count(//CanPorts/CanPort[@parent=$hostname]) != 0">
<CanPorts>
<xsl:apply-templates select="//CanPorts/CanPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</CanPorts>
</xsl:if>
<xsl:if test="count(//EthernetPorts/EthernetPort[@parent=$hostname]) != 0">
<EthernetPorts>
<xsl:apply-templates
select="//EthernetPorts/EthernetPort[@parent=$hostname]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</EthernetPorts>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="DataFrame">
<xsl:variable name="framename" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="//Path[@parent=$framename]">
<xsl:sort select="@name" data-type="text" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="Path">
<xsl:variable name="pathname" select="@name"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="//Node[@parent=$pathname]">
<xsl:sort select="@sequenceNumber" data-type="text" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- Do not save attributes parent and ID for child elements -->
<xsl:template match="CanPort|LinPort|EthernetPort|Node">
<xsl:copy>
<xsl:apply-templates select="@*">
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- This template matches @parent and @id and does nothing -->
<xsl:template match="@parent | @id"/>
</xsl:stylesheet>