Search code examples
xsltxmigraphml

XSLT: How to find source and target Xpath for the edge?


I want to write an xslt file to transfer an xmi file in a graphical file. But I meet the problem that the edge can not connect the right source node and target node. I have tried already two weeks. But I am still confused. Please help me. Thanks a million.

The original code is:

<?xml version="1.0" encoding="UTF-8"?>
<xml xmlns:xmi="#">
<element xmi:id="BasicElement-Line1" name="Line1" xmi:type="association"/>

<element xmi:id="BasicElement-Line2" name="Line2" xmi:type="association"/>

<element xmi:id="BasicElement-Object1" name="Object1" xmi:type="class">
    <ownedAttribute xmi:type="Property" name="input" type="BasicElement-Object2" association="BasicElement-Line1"/>
    <ownedAttribute xmi:type="Property" name="output" type="BasicElement-Object3" association="BasicElement-Line2"/>
</element>

<element xmi:id="BasicElement-Object2" name="Object2" xmi:type="class">
</element>

<element xmi:id="BasicElement-Object3" name="Object3" xmi:type="class">
</element>
</xml>

and my aim code is:

<?xml version="1.0" encoding="UTF-8"?>
<xmi xmlns:y="##">
   <edge target="N1002D" source="N1001B" id="N10005">
      <y:PolyLineEdge>
         <y:Arrows target="none" source="none" />
      </y:PolyLineEdge>
   </edge>
   <edge target="N1002D" source="N1001B" id="N10010">
      <y:PolyLineEdge>
         <y:Arrows target="none" source="none" />
      </y:PolyLineEdge>
   </edge>
   <node id="N1001B">
      <y:NodeLabel>BasicElement-Object1</y:NodeLabel>
   </node>
   <node id="N1002D">
      <y:NodeLabel>BasicElement-Object2</y:NodeLabel>
   </node>
   <node id="N10033">
      <y:NodeLabel>BasicElement-Object3</y:NodeLabel>
   </node>
</xmi>

Because there will be more "class" element in the future. So I used "{generate-id()}" to define the node IDs. But when I do that, I found the edge can not find the way of source node and target node. So I have already worked on it two weeks and have no idea on it. Please help me, I really appreciate.


Solution

  • I'm not really familiar with XMI and the target format, but here's something that should fit your description.

    Source:

    <?xml version="1.0" encoding="UTF-8"?>
    <xml xmlns:xmi="#">
        <element xmi:id="BasicElement-Line1" name="Line1" xmi:type="association">
             <ownedEnd xmi:type="Property" type="BasicElement-Object1" association="BasicElement-Line1"/>
        </element>
    
        <element xmi:id="BasicElement-Line2" name="Line2" xmi:type="association">
            <ownedEnd xmi:type="Property" type="BasicElement-Object1" association="BasicElement-Line2"/>
        </element>
    
        <element xmi:id="BasicElement-Object1" name="Object1" xmi:type="class">
            <ownedAttribute xmi:type="Property" name="input" type="BasicElement-Object2" association="BasicElement-Line1"/>
            <ownedAttribute xmi:type="Property" name="output" type="BasicElement-Object3" association="BasicElement-Line2"/>
        </element>
    
        <element xmi:id="BasicElement-Object2" name="Object2" xmi:type="class">
        </element>
    
        <element xmi:id="BasicElement-Object3" name="Object3" xmi:type="class">
        </element>
    </xml>
    

    Transformed with (adjust the namespaces to the correct uris):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xmi="#" xmlns:y="##"
    exclude-result-prefixes="xmi" version="1.0">
    <xsl:output indent="yes"/>
    
    <xsl:template match="xml">
        <xmi>
            <xsl:apply-templates select="element"/>
        </xmi>
    </xsl:template>
    
    <xsl:template match="element[@xmi:type='class']">
        <node id="{generate-id()}">
            <y:NodeLabel>
                <xsl:value-of select="@xmi:id"/>
            </y:NodeLabel>
            <y:UMLClassNode/>
        </node>
    </xsl:template>
    
    <xsl:template match="element[@xmi:type='association']">
        <!-- association name -->
        <xsl:variable name="association" select="ownedEnd/@association"/>
        <!-- id of source -->
        <xsl:variable name="ownedEnd-type" select="ownedEnd/@type"/>
        <!-- using association variable to select the correct id of target -->
        <xsl:variable name="ownedAttribute-type"
            select="//element[@xmi:id = $ownedEnd-type]/ownedAttribute[@association = $association]/@type"/>
        <edge id="{ generate-id() }" 
            source="{ generate-id( /xml/element[@xmi:id = $ownedEnd-type] ) }"
            target="{ generate-id( /xml/element[@xmi:id = $ownedAttribute-type] ) }">
            <y:PolyLineEdge>
                <y:Arrows source="none" target="none"/>
            </y:PolyLineEdge>
        </edge>
    </xsl:template>
    
    </xsl:stylesheet>
    

    gives you:

    <xmi xmlns:y="##">
       <edge id="d0e3" source="d0e13" target="d0e20">
          <y:PolyLineEdge>
             <y:Arrows source="none" target="none"/>
          </y:PolyLineEdge>
       </edge>
       <edge id="d0e8" source="d0e13" target="d0e23">
          <y:PolyLineEdge>
             <y:Arrows source="none" target="none"/>
          </y:PolyLineEdge>
       </edge>
       <node id="d0e13">
           <y:NodeLabel>BasicElement-Object1</y:NodeLabel>
           <y:UMLClassNode/>
       </node>
       <node id="d0e20">
           <y:NodeLabel>BasicElement-Object2</y:NodeLabel>
           <y:UMLClassNode/>
       </node>
       <node id="d0e23">
           <y:NodeLabel>BasicElement-Object3</y:NodeLabel>
           <y:UMLClassNode/>
       </node>
    </xmi>