0

I'm asking for help with replacing values from two XML files using XSLT 1.0. I believe I'm close but need some guidance on fine-tuning what I've got so far.

First the problem: These two XML files are essentially the same. I'm replacing two nodes in the first file with nodes from a second file and all of its children but my current implementation is creating duplicates. I'm certain it's because my XPath is returning all of the nodes that I've given it but I don't know how to adjust the predicate so that it only replaces if it matches a sibling node - specifically the .

File 1 - Networks.xml

<?xml version="1.0" encoding="utf-8"?>
<Network_Records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Networks.xsd">
  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS1</SwitchName>
    <RackNumber>T5553</RackNumber>
    <Elevation>A14</Elevation>
    <RoomLocation>Phoenix</RoomLocation> 
   <NetworkSwitchConfigModule>switch_1_phx.txt</NetworkSwitchConfigModule>
    <Override>false</Override>
  </NetworkSwitch>

  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS2</SwitchName>
    <RackNumber>Fill</RackNumber>
    <Elevation>Fill</Elevation>
    <RoomLocation>Fill</RoomLocation>
   <NetworkSwitchConfigModule>switch_2_cle.txt</NetworkSwitchConfigModule>
    <Override>false</Override>
  </NetworkSwitch>

File 2 - Networks_2.xml

<?xml version="1.0" encoding="utf-8"?>
<Network_Records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Networks.xsd">
<NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS1</SwitchName>
    <RackNumber>Fill</RackNumber>
    <Elevation>Fill</Elevation>
    <RoomLocation>Fill</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J5)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J5)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>
  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS2</SwitchName>
    <RackNumber>REPLACE</RackNumber>
    <Elevation>REPLACE</Elevation>
    <RoomLocation>REPLACE</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J4)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J7)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>
</Network_Records>

My XSLT so far -

<xsl:output method="xml" indent="yes" version="1.0" encoding="utf-8" />

<xsl:variable name="tempNetworks" select="document('Networks_2.xml')"/>

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

<xsl:template match="NetworkSwitchConfigModule">
   <xsl:copy-of select="$tempNetworks/Network_Records/NetworkSwitch/NetworkModule"/>
</xsl:template>

<xsl:template match="Override">
</xsl:template>

Actual results - final.xml

<?xml version="1.0" encoding="utf-8"?>
<Network_Records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Networks.xsd">
  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS1</SwitchName>
    <RackNumber>T5553</RackNumber>
    <Elevation>A14</Elevation>
    <RoomLocation>Phoenix</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J5)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J5)</DeviceName>
      </NetworkPort>
    </NetworkModule>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J4)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J7)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>

  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS2</SwitchName>
    <RackNumber>REPLACE</RackNumber>
    <Elevation>REPLACE</Elevation>
    <RoomLocation>REPLACE</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J5)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J5)</DeviceName>
      </NetworkPort>
    </NetworkModule>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J4)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J7)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>
</Network_Records>

Expected results - final.xml

<?xml version="1.0" encoding="utf-8"?>
<Network_Records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Networks.xsd">
  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS1</SwitchName>
    <RackNumber>T5553</RackNumber>
    <Elevation>A14</Elevation>
    <RoomLocation>Phoenix</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J5)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J5)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>

  <NetworkSwitch>
    <ChannelID>A</ChannelID>
    <SwitchName>OPS2</SwitchName>
    <RackNumber>REPLACE</RackNumber>
    <Elevation>REPLACE</Elevation>
    <RoomLocation>REPLACE</RoomLocation>
    <NetworkModule>
      <ModuleNumber>2</ModuleNumber>
      <NetworkPort>
        <PortNumber>1</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>ASA1 (J4)</DeviceName>
      </NetworkPort>
      <NetworkPort>
        <PortNumber>10</PortNumber>
        <DeviceType>Processor</DeviceType>
        <DeviceName>CWA2 (J7)</DeviceName>
      </NetworkPort>
    </NetworkModule>
  </NetworkSwitch>
</Network_Records>

1 Answers1

0

Just change your templates to

<xsl:template match="NetworkSwitchConfigModule">
    <xsl:copy-of select="$tempNetworks/Network_Records/NetworkSwitch[SwitchName = current()/../SwitchName]/NetworkModule"/>
</xsl:template>

<xsl:template match="Override" />

You have been missing the predicate to select the right nodes from the second XML. Hence you were copying all NetworkModule elements and not only the ones you wanted. The predicate

SwitchName = current()/../SwitchName

compares the value of the SwitchName from the second file to the parent SwitchName of the currently matched template rule.

zx485
  • 28,498
  • 28
  • 50
  • 59
  • Thank you very much. It successfully transformed it. Would you mind explaining how you implemented the predicate? `NetworkSwitch[SwitchName = current()/../SwitchName]/NetworkModule` It seems like you're selecting the node set by starting at the current SwitchName, then traversing up and then back down. – user7406684 Nov 10 '19 at 21:15
  • This is only half of what the predicate did. Have a look [at this SO answer: Current node vs. Context node in XSLT/XPath?](https://stackoverflow.com/a/1022354/1305969). In the above predicate `SwitchName` is relative to the context node (of the XPath) and `current()/../SwitchName` is, as indicated by the [current() function](https://www.w3schools.com/xml/func_current.asp), relative to the current template. – zx485 Nov 10 '19 at 21:25