calaedo
calaedo

Reputation: 333

XSLT transform to tree XML structure via attribute

I have some XML Files with following flat structure:

<managedObject class="MGW" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454" id="192614000001726941">
  <list name="mgwOptions">
    <p>M3UA Interface (No 50035)</p>
  </list>
  <p name="name">MGW_A</p>
</managedObject>
<managedObject class="ATM" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454/ATM-1" id="192614000003145148">
  <p name="lastSuccessfulUploadTimeStamp">21/07/15 01:32:40</p>
</managedObject>
<managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-0" id="192614000003415034">
  <p name="prSectionSdhExchangeTerminalIndex">1</p>
  <p name="protectionSwitchingMode">REV</p>
  <p name="protocolVariant">MSP</p>
  <p name="switchingDirection">WO</p>
  <p name="waitToRestoreTime">300</p>
  <p name="woSectionSdhExchangeTerminalIndex">0</p>
</managedObject>
<managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-1" id="192614000003415035">
  <p name="prSectionSdhExchangeTerminalIndex">3</p>
  <p name="protectionSwitchingMode">REV</p>
  <p name="protocolVariant">MSP</p>
  <p name="switchingDirection">WO</p>
  <p name="waitToRestoreTime">300</p>
  <p name="woSectionSdhExchangeTerminalIndex">2</p>
</managedObject>

I want to transform with XSL in a more treelike structure according to the distName and class attributes of managedObjects elements. Something like:

<?xml version="1.0"?>
<managedObject class="MGW" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454" id="192614000001726941">
  <list name="mgwOptions">
    <p>M3UA Interface (No 50035)</p>
  </list>
  <p name="name">MGW_A</p>
  <managedObject class="ATM" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454/ATM-1" id="192614000003145148">
    <p name="lastSuccessfulUploadTimeStamp">21/07/15 01:32:40</p>
    <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-0" id="192614000003415034">
      <p name="prSectionSdhExchangeTerminalIndex">1</p>
      <p name="protectionSwitchingMode">REV</p>
      <p name="protocolVariant">MSP</p>
      <p name="switchingDirection">WO</p>
      <p name="waitToRestoreTime">300</p>
      <p name="woSectionSdhExchangeTerminalIndex">0</p>
    </managedObject>
    <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-1" id="192614000003415035">
      <p name="prSectionSdhExchangeTerminalIndex">3</p>
      <p name="protectionSwitchingMode">REV</p>
      <p name="protocolVariant">MSP</p>
      <p name="switchingDirection">WO</p>
      <p name="waitToRestoreTime">300</p>
      <p name="woSectionSdhExchangeTerminalIndex">2</p>
    </managedObject>
  </managedObject>
</managedObject>

Is something like that generical and simple solveable? my files consists of approxemately 100,000 managed objects which have a different class and different distName paths.

Upvotes: 0

Views: 96

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 116992

A better explanation would have been useful. Staring at the example, I don't see what role the class attribute plays here; it seems that children are linked to their parent by comparing the substring of distName before the last / with the entire distNamestring of the parent.

There's also no apparent way to determine who the "progenitors" are, other than by looking for orphans using the above rule.

Note also that your input is not well-formed XML: you must have a single root element.

Now, if you can use XSLT 2.0, try:

XSLT 2.0

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://www.example.com/my"
exclude-result-prefixes="my">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:function name="my:substring-before-last">
    <xsl:param name="string"/> 
    <xsl:param name="delimiter"/> 
    <xsl:value-of select="tokenize($string, $delimiter)[position()!=last()]" separator="{$delimiter}"/>
</xsl:function>

<xsl:key name="child" match="managedObject" use="my:substring-before-last(@distName, '/')" />
<xsl:key name="parent" match="managedObject" use="@distName" />

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

<xsl:template match="/input">
    <output>
        <!-- select progenitors -->
        <xsl:apply-templates select="managedObject[not(key('parent', my:substring-before-last(@distName, '/')))]" />
    </output>
</xsl:template>

<xsl:template match="managedObject">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <!-- select children -->
        <xsl:apply-templates select="key('child', @distName)"/> 
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Applied to the following well-formed input:

XML

<input>
    <managedObject class="MGW" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454" id="192614000001726941">
      <list name="mgwOptions">
        <p>M3UA Interface (No 50035)</p>
      </list>
      <p name="name">MGW_A</p>
    </managedObject>
    <managedObject class="ATM" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454/ATM-1" id="192614000003145148">
      <p name="lastSuccessfulUploadTimeStamp">21/07/15 01:32:40</p>
    </managedObject>
    <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-0" id="192614000003415034">
      <p name="prSectionSdhExchangeTerminalIndex">1</p>
      <p name="protectionSwitchingMode">REV</p>
      <p name="protocolVariant">MSP</p>
      <p name="switchingDirection">WO</p>
      <p name="waitToRestoreTime">300</p>
      <p name="woSectionSdhExchangeTerminalIndex">0</p>
    </managedObject>
    <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-1" id="192614000003415035">
      <p name="prSectionSdhExchangeTerminalIndex">3</p>
      <p name="protectionSwitchingMode">REV</p>
      <p name="protocolVariant">MSP</p>
      <p name="switchingDirection">WO</p>
      <p name="waitToRestoreTime">300</p>
      <p name="woSectionSdhExchangeTerminalIndex">2</p>
    </managedObject>
</input>

the result is:

<?xml version="1.0" encoding="utf-8"?>
<output>
   <managedObject class="MGW" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454"
                  id="192614000001726941">
      <list name="mgwOptions">
         <p>M3UA Interface (No 50035)</p>
      </list>
      <p name="name">MGW_A</p>
      <managedObject class="ATM" version="U5.0EP2" distName="PLMN-PLMN/MGW-219454/ATM-1"
                     id="192614000003145148">
         <p name="lastSuccessfulUploadTimeStamp">21/07/15 01:32:40</p>
         <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-0"
                        id="192614000003415034">
            <p name="prSectionSdhExchangeTerminalIndex">1</p>
            <p name="protectionSwitchingMode">REV</p>
            <p name="protocolVariant">MSP</p>
            <p name="switchingDirection">WO</p>
            <p name="waitToRestoreTime">300</p>
            <p name="woSectionSdhExchangeTerminalIndex">0</p>
         </managedObject>
         <managedObject class="IFPG" version="A10TOP" distName="PLMN-PLMN/MGW-219454/ATM-1/IFPG-1"
                        id="192614000003415035">
            <p name="prSectionSdhExchangeTerminalIndex">3</p>
            <p name="protectionSwitchingMode">REV</p>
            <p name="protocolVariant">MSP</p>
            <p name="switchingDirection">WO</p>
            <p name="waitToRestoreTime">300</p>
            <p name="woSectionSdhExchangeTerminalIndex">2</p>
         </managedObject>
      </managedObject>
   </managedObject>
</output>

Upvotes: 2

Related Questions