删除属性和空元素

时间:2014-12-03 12:15:38

标签: xslt

在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>
  1. 我还创建了空的元素(CanPorts,LinPorts,EthernetPorts)。我如何摆脱这些?
  2. 我想摆脱@parent属性。我已设法为除Path之外的所有元素执行此操作。我如何摆脱Path.parent?

1 个答案:

答案 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>