0

I am trying to trim an XML document into a new XML document. I have the following XML:

<rpc-reply>
  <configuration changed-seconds="1450987515" changed-localtime="2015-12-24 20:05:15 UTC">
    <routing-instances>
      <instance>
        <name>SOMENAME</name>
        <instance-type>virtual-router</instance-type>
        <interface>
          <name>lo0.1</name>
        </interface>
        <protocols>
          <bgp>
            <group>
              <name>EBGP-TEST</name>
              <type>external</type>
              <neighbor>
                <name>1.1.1.1</name>
                <peer-as>7222</peer-as>
              </neighbor>
            </group>
          </bgp>
          <ospf>
            <area>
              <name>0.0.0.0</name>
              <comment>SOME COMMENT</comment>
              <interface>
                <name>all</name>
              </interface>
            </area>
          </ospf>
        </protocols>
      </instance>
    </routing-instances>
  </configuration>
  <cli>
    <banner>[edit]</banner>
  </cli>
</rpc-reply>

This is what I need:

<rpc-reply>
  <configuration changed-seconds="1450987515" changed-localtime="2015-12-24 20:05:15 UTC">
    <routing-instances>
      <instance>
        <name>SOMENAME</name>
        <protocols>
          <ospf>
            <area>
              <name>0.0.0.0</name>
              <comment>SOME COMMENT</comment>
              <interface>
                <name>all</name>
              </interface>
            </area>
          </ospf>
        </protocols>
      </instance>
    </routing-instances>
  </configuration>
</rpc-reply>

Here is the XSLT code I am using:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="match:ns" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <ns:WhiteList>
   <name>area</name>
   <name>interface</name>
   <name>instance</name>
   <name>metric</name>
  </ns:WhiteList>

  <xsl:template match="node()|@*">
      <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
  </xsl:template>

 <xsl:template match="*[not(descendant-or-self::*[name()=document('')/*/ns:WhiteList/*])]"/>

 </xsl:stylesheet>

And it almost works:

<rpc-reply>
  <configuration changed-seconds="1450987515" changed-localtime="2015-12-24 20:05:15 UTC">
    <routing-instances>
      <instance>
        <interface/>
        <protocols>
          <ospf>
            <area>
              <interface/>
            </area>
          </ospf>
        </protocols>
      </instance>
    </routing-instances>
  </configuration>
</rpc-reply>

I just need the child "<name>" for the interesting elements (if there is one there) and bonus if I can somehow get the "<comment>" right above "<interface>" Tried different combinations but not sure how to do it.

har07
  • 88,338
  • 12
  • 84
  • 137
salparadise
  • 5,699
  • 1
  • 26
  • 32

1 Answers1

3

I just need the child "<name>" for the interesting elements (if there is one there)

You could add a template to handle it specifically:

<xsl:template match="name[name(..)=document('')/*/ns:WhiteList/*]" priority="1">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

and bonus if I can somehow get the "<comment>" right above "<interface>"

Similarly:

<xsl:template match="comment[following-sibling::*[1][self::interface]]" priority="1">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

To avoid code repetition, try a more streamlined version:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ns="match:ns">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<ns:WhiteList>
    <name>area</name>
    <name>interface</name>
    <name>instance</name>
    <name>metric</name>
</ns:WhiteList>

<xsl:template match="node()|@*" name="identity">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[not(descendant-or-self::*[name()=document('')/*/ns:WhiteList/*])]"/>

<xsl:template match="name[name(..)=document('')/*/ns:WhiteList/*]" priority="1">
    <xsl:call-template name="identity"/>
</xsl:template>

<xsl:template match="comment[following-sibling::*[1][self::interface]]" priority="1">
    <xsl:call-template name="identity"/>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51