XSLT: Select key() OR another key()

417 Views Asked by At

I have elements connector which has source and target. But source can be sometimes one element sometimes another (initial node or activity). So I have 2 keys for that. I wan to use either one key or the other. Sample of my XML input:

            <packagedElement>
                <node xmi:type="uml:InitialNode" xmi:id="EAID_a" name="ActivityInitial">
                    <outgoing xmi:idref="EAID_A7A0C176_5CCC_4bf2_AED2_AEB05FB741AF"/>
                </node>
                <group xmi:type="uml:ActivityPartition" xmi:id="EAID_b" name="Partition_1">
                    <node xmi:idref="EAID_c"/>
                </group>
                <packagedElement xmi:type="uml:Activity" xmi:id="EAID_c" name="Activity1"/>
                <group xmi:type="uml:ActivityPartition" xmi:id="EAID_d" name="Partition_2">
                    <node xmi:idref="EAID_e"/>
                </group>
                <packagedElement xmi:type="uml:Activity" xmi:id="EAID_e" name="Activity2"/>
            </packagedElement>
            ...
            <connector xmi:idref="EAID_A7A0C176_f">
                <source xmi:idref="EAID_a"/>        
                <target xmi:idref="EAID_c"/>
            </connector>
            <connector xmi:idref="EAID_CEB43B7F_g"/>
                <source xmi:idref="EAID_c"/>
                <target xmi:idref="EAID_e"/>
            </connector>

This is my XSLT:


    <xsl:key name="grp" match="group" use="node/@xmi:idref" />
    <xsl:key name="ini" match="*[@xmi:type='uml:InitialNode']" use="@xmi:id" />

    ...

    <connector xmi:idref="EAID_CONNECTR{substring(@xmi:id, 14, 28)}">
         <source xmi:idref="(EAID_LIFELINE{key('grp', @source)/substring(@xmi:id, 14, 28)})({key('ini', @source)/@xmi:id})"/>
         <target xmi:idref="EAID_LIFELINE{key('grp', @target)/substring(@xmi:id, 14, 28)}"/>
    </connector>

For two connectors WRONG xml output looks like that:

 <connector xmi:idref="EAID_CONNECTR_f">
        <source xmi:idref="(EAID_LIFELINE)(EAID_a)"/>
        <target xmi:idref="EAID_LIFELINE_c"/>
 </connector>
 <connector xmi:idref="EAID_CONNECTR_g">
        <source xmi:idref="(EAID_LIFELINE_c)()"/>
        <target xmi:idref="EAID_LIFELINE_e"/>
 </connector>

But XML output should look like that:

 <connector xmi:idref="EAID_CONNECTR_5CCC_4bf2_AED2_AEB05FB741AF">
        <source xmi:idref="EAID_a"/>
        <target xmi:idref="EAID_LIFELINE_c"/>
 </connector>
 <connector xmi:idref="EAID_CONNECTR_ED15_4f03_8D9B_8EF054BD458D">
        <source xmi:idref="EAID_LIFELINE_c"/>
        <target xmi:idref="EAID_LIFELINE_e"/>
 </connector>

So, if I am using key "grp" there should be prefix EAID_LIFELINE, but if I am using key "ini" there should have all id without prefix. How edit XSLT for what i want?

1

There are 1 best solutions below

0
Tim C On

I could make sense of how your current XSLT corresponds to your XML and your expected output, partially because your XSLT is looking for a @source attribute, which doesn't exist in your XML.

But to answer in general terms, if you are indeed using XSLT 2.0, this could be a case for the if ... else ... construct, so you could write the expression like so:

  <source xmi:idref="{
        if (key('grp', @source)) 
        then concat('EAID_LIFELINE', key('grp', @source)/substring(@xmi:id, 14, 28)) 
        else key('ini', @source)/@xmi:id
    }"/>

Do also note, that the use of the "ini" key is confusing...

key('ini', @source)/@xmi:id

Because the "ini" key has a "use" attribute of @xmi:id, then it the key would only return anything if @source equals the @xmi:id on the node element. In other words key('ini', @source)/@xmi:id is equal to just @source.