4

I have a problem extracting some data out of a XML file. I still have problems to figure out how to handle the ph:Attribute of a ph:Element if there are more than one but the output should look like (s_rel0 = 5, par_s_rel0 = 5) and not like (s_rel0 = 5)(par_s_rel0 = 5). Maybe an if-then case!?

And the second conection should consist of flange_b and not of flange_a. I searched for while the mistake but could not find it.

Do you have any idea where I did a mistake!? Thanks for your help.

XML:

<?xml version="1.0" encoding="UTF-8"?>
    <ph:Graphs xmlns:ph="http://www.merge.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <ph:Graph name="mass_spring_mo">
            <ph:Element id="0" type="Fixed">
                <ph:Port id="1" type="port">
                    <ph:Attribute>
                        <ph:AttributeField name="type" value="string"/>
                        <ph:AttributeField name="name" value="type"/>
                        <ph:AttributeField name="value" value="flange"/>
                    </ph:Attribute>
                </ph:Port>
            </ph:Element>
            <ph:Element id="2" type="Spring">
                <ph:Attribute>
                    <ph:AttributeField name="type" value="int"/>
                    <ph:AttributeField name="name" value="s_rel0"/>
                    <ph:AttributeField name="value" value="5"/>
                </ph:Attribute>
                <ph:Attribute>
                    <ph:AttributeField name="type" value="int"/>
                    <ph:AttributeField name="name" value="par_s_rel0"/>
                    <ph:AttributeField name="value" value="5"/>
                </ph:Attribute>
                <ph:Port id="3" type="port">
                    <ph:Attribute>
                        <ph:AttributeField name="type" value="string"/>
                        <ph:AttributeField name="name" value="type"/>
                        <ph:AttributeField name="value" value="flange_a"/>
                    </ph:Attribute>
                </ph:Port>
                <ph:Port id="4" type="port">
                    <ph:Attribute>
                        <ph:AttributeField name="type" value="string"/>
                        <ph:AttributeField name="name" value="type"/>
                        <ph:AttributeField name="value" value="flange_b"/>
                    </ph:Attribute>
                </ph:Port>
            </ph:Element>
            <ph:Element id="5" type="Mass">
                <ph:Port id="6" type="port">
                    <ph:Attribute>
                        <ph:AttributeField name="type" value="string"/>
                        <ph:AttributeField name="name" value="type"/>
                        <ph:AttributeField name="value" value="flange_a"/>
                    </ph:Attribute>
                </ph:Port>
            </ph:Element>
            <ph:Edge id="7" sourceid="1" targetid="3"/>
            <ph:Edge id="8" sourceid="4" targetid="6"/>
        </ph:Graph>
    </ph:Graphs>

XSLT:

<?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ph="http://www.merge.something.com">

        <xsl:output indent="yes" method="text"/>

        <xsl:template match="/">
            <xsl:apply-templates select="ph:Graphs/ph:Graph"/>
        </xsl:template>

        <xsl:template match="ph:Graph">
            <xsl:text>model</xsl:text>
            <xsl:value-of select="@name"/>
            <xsl:text></xsl:text>
            <xsl:apply-templates select="ph:Element"/>
            <xsl:text>equation</xsl:text>
            <xsl:apply-templates select="ph:Edge"/>
            <xsl:text>end</xsl:text>
            <xsl:value-of select="@name"/>
            <xsl:text>;</xsl:text>
        </xsl:template>

        <xsl:template match="ph:Element">
            <xsl:text> Components.</xsl:text>
            <xsl:value-of select="@type"/>
            <xsl:text > </xsl:text>
            <xsl:value-of select="translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>
            <xsl:value-of select="@id"/>
            <xsl:apply-templates select="ph:Attribute"/>
            <xsl:text>;</xsl:text>
         </xsl:template>

         <xsl:template match="ph:Element/ph:Attribute">
             <xsl:choose>
                 <xsl:when test="ph:AttributeField[@name = 'type' and @value='int']">
                     <xsl:text>(</xsl:text>
                     <xsl:value-of select="ph:AttributeField[@name = 'name']/@value"/>
                     <xsl:text> = </xsl:text>
                     <xsl:value-of select="ph:AttributeField[@name = 'value']/@value" />
                     <xsl:text>)</xsl:text>
                 </xsl:when>
                 <xsl:when test="ph:AttributeField[@name = 'type' and @value='string']">
                     <xsl:text>(</xsl:text>
                     <xsl:value-of select="ph:AttributeField[@name = 'name']/@value"/>
                     <xsl:text> = '</xsl:text>
                     <xsl:value-of select="ph:AttributeField[@name = 'value']/@value" />
                     <xsl:text>')</xsl:text>
                 </xsl:when>
             </xsl:choose>
         </xsl:template>

         <xsl:template match="ph:Port/ph:Attribute">
             <xsl:if test="ph:AttributeField/@value=type">
                 <xsl:apply-templates select="ph:AttributeField"/>
             </xsl:if>
         </xsl:template>

         <xsl:template match="ph:AttributeField">
         </xsl:template>

         <xsl:template match="ph:Edge">
             <xsl:variable name="sourceid" select="@sourceid"/>
             <xsl:variable name="targetid" select="@targetid"/>
             <xsl:variable name="SourceElement" select="//ph:Element[ph:Port[@id = $sourceid]]"/>
             <xsl:variable name="TargetElement" select="//ph:Element[ph:Port[@id = $targetid]]"/>
             <xsl:text> connect(</xsl:text>
             <xsl:value-of select="translate($SourceElement/@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
             <xsl:value-of select="$SourceElement/@id" />
             <xsl:text>.</xsl:text>
             <xsl:value-of select="$SourceElement/ph:Port/ph:Attribute/ph:AttributeField[@name = 'value']/@value" />
             <xsl:text>,</xsl:text>
             <xsl:value-of select="translate($TargetElement/@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
             <xsl:value-of select="$TargetElement/@id" />
             <xsl:text>.</xsl:text>
             <xsl:value-of select="$TargetElement/ph:Port/ph:Attribute/ph:AttributeField[@name = 'value']/@value" />
             <xsl:text >);</xsl:text>
         </xsl:template>

    </xsl:stylesheet>

Disired output:

model mass_spring_mo
 Components.Fixed fixed0;
 Components.Spring spring2(s_rel0 = 5, par_s_rel0 = 5);
 Components.Mass mass5;
equation
 connect(fixed0.flange,spring2.flange_a);
 connect(spring2.flange_b,mass5.flange_a);
end mass_spring_mo;
1
  • 2
    Please mark which answer you feel is correct. Commented Dec 7, 2012 at 10:02

4 Answers 4

7

Here is how you do if-else in xslt

<xsl:choose>
  <xsl:when test="@ordered=1">
    <ol>
      <xsl:apply-templates select="item-ordered" />
    </ol>
  </xsl:when>
  <xsl:otherwise>
    <ul>
      <xsl:apply-templates select="item-unordered" />
    </ul>
  </xsl:otherwise>
</xsl:choose>
Sign up to request clarification or add additional context in comments.

Comments

3

the output should look like (s_rel0 = 5, par_s_rel0 = 5)

About parenthesis, just add/append some condition to the related template:

<xsl:template match="ph:Element/ph:Attribute">

        <xsl:if test="count(preceding-sibling::*[1][local-name()='Attribute'])=0">
            <xsl:text>(</xsl:text>
        </xsl:if>

    <!-- xsl:choose -->

    <xsl:if test="count(following-sibling::*[1][local-name()='Attribute'])=0">
            <xsl:text>)</xsl:text>
        </xsl:if>

    <xsl:if test="count(following-sibling::*[1][local-name()='Attribute'])=1">
            <xsl:text>,</xsl:text>
    </xsl:if>

</xsl:template>

second conection should consist of flange_b and not of flange_a

About the wrong connection, you need to change two lines in the last templates, in particular those lines selecting the value:

<xsl:value-of select="$SourceElement/
   ph:Port[@id=$sourceid]/
   ph:Attribute/ph:AttributeField[@name = 'value']/@value" />

<xsl:value-of select="$TargetElement/
   ph:Port[@id=$targetid]/
   ph:Attribute/ph:AttributeField[@name = 'value']/@value" />

This is because with:

//ph:Element[ph:Port[@id = $sourceid]]

You are selecting the entire ph:Element node, so you need re-match afterward. The fact that your tamplate works for the first connection is just a case.

1 Comment

count(preceding-sibling::*[1][local-name()='Attribute'])=0 is written more nicely as not(preceding-sibling::*[1]/self::ph:Attribute)
2

In my humble opinion, a good XSLT code has no if/else structure. Here is a version only based on template overrides:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ph="http://www.merge.something.com">

  <xsl:output indent="yes" method="text"/>
  <xsl:key name="ports" match="//ph:Element/ph:Port" use="@id" />

  <xsl:template match="/">
    <xsl:apply-templates select="ph:Graphs/ph:Graph"/>
    <xsl:text>&#10;</xsl:text><!-- new line -->
  </xsl:template>

  <xsl:template match="ph:Graph">
    <xsl:text>model </xsl:text>
    <xsl:value-of select="@name"/>
    <xsl:text>&#10;</xsl:text><!-- new line -->
    <xsl:apply-templates select="ph:Element"/>
    <xsl:text>equation</xsl:text>
    <xsl:text>&#10;</xsl:text><!-- new line -->
    <xsl:apply-templates select="ph:Edge"/>
    <xsl:text>end </xsl:text>
    <xsl:value-of select="@name"/>
    <xsl:text>;</xsl:text>
  </xsl:template>

  <!-- ph:Element with at least one ph:Attribute child -->
  <xsl:template match="ph:Element[ph:Attribute]">
    <xsl:text> Components.</xsl:text>
    <xsl:value-of select="@type"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>
    <xsl:value-of select="@id"/>
    <xsl:text>(</xsl:text>
    <xsl:apply-templates select="ph:Attribute"/>
    <xsl:text>)</xsl:text>
    <xsl:text>;&#10;</xsl:text>
  </xsl:template>

  <!-- ph:Element by default -->
  <xsl:template match="ph:Element">
    <xsl:text> Components.</xsl:text>
    <xsl:value-of select="@type"/>
    <xsl:text > </xsl:text>
    <xsl:value-of select="translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>
    <xsl:value-of select="@id"/>
    <xsl:apply-templates select="ph:Attribute"/>
    <xsl:text>;&#10;</xsl:text>
  </xsl:template>

  <!-- Port/Attribute elements are rendered as : "type.value" -->
  <xsl:template match="ph:Port/ph:Attribute">
    <xsl:apply-templates select="ph:AttributeField[@name='type']" />
    <xsl:text>.</xsl:text>
    <xsl:apply-templates select="ph:AttributeField[@name='value']" />
  </xsl:template>

  <!-- First element attribute is rendered as : "name = value" -->
  <xsl:template match="ph:Element/ph:Attribute">
    <xsl:apply-templates select="ph:AttributeField[@name='name']" />
    <xsl:text> = </xsl:text>
    <xsl:apply-templates select="ph:AttributeField[@name='value']" />
  </xsl:template>

  <!-- Other element attributes are rendered as : ", name = value" -->
  <xsl:template match="ph:Element/ph:Attribute[position() &gt; 1]">
    <xsl:text>, </xsl:text>
    <xsl:apply-templates select="ph:AttributeField[@name='name']" />
    <xsl:text> = </xsl:text>
    <xsl:apply-templates select="ph:AttributeField[@name='value']" />
  </xsl:template>

  <!-- By default, an AttributeField is rendered by displaying its "value" attribute -->
  <xsl:template match="ph:AttributeField">
    <xsl:value-of select="@value" />
  </xsl:template>

  <!-- "type" AttributeFields are not displayed -->
  <xsl:template match="ph:AttributeField[@name='type']" />

  <!-- "value" AttributeField whose "type" brother says that it's a 'string' are rendered with single quotes (but only for ph:Element not for ph:Port)-->
  <xsl:template match="ph:Element/ph:Attribute/ph:AttributeField[@name='value'][../ph:AttributeField[@name='type']/@value = 'string']">
    <xsl:text>'</xsl:text>
    <xsl:value-of select="@value" />
    <xsl:text>'</xsl:text>
  </xsl:template>

  <xsl:template match="ph:Port">
    <xsl:value-of select="translate(../@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
    <xsl:value-of select="../@id" />
    <xsl:apply-templates select="ph:Attribute" />
  </xsl:template>

  <xsl:template match="ph:Edge">
    <xsl:variable name="SourceElement" select="key('ports', @sourceid)"/>
    <xsl:variable name="TargetElement" select="key('ports', @targetid)"/>
    <xsl:text> connect(</xsl:text>
    <xsl:apply-templates select="$SourceElement" />
    <xsl:text>, </xsl:text>
    <xsl:apply-templates select="$TargetElement" />
    <xsl:text >);</xsl:text>
    <xsl:text>&#10;</xsl:text><!-- new line -->
  </xsl:template>

</xsl:stylesheet>

By the way... I added a xsl:key element to index ph:Ports which can save processing time compared to //ph:Element[ph:Port[@id = $sourceid]]

Comments

0

<xsl:template match="/">
<xsl:apply-templates select="ph:Graphs/ph:Graph"/>
</xsl:template>

<xsl:template match="ph:Graph">
<xsl:text>model </xsl:text>
<xsl:value-of select="@name"/>
<xsl:apply-templates select="ph:Element"/>
 <xsl:text>equation</xsl:text>
        <xsl:apply-templates select="ph:Edge"/>
        <xsl:text>end</xsl:text>
        <xsl:value-of select="@name"/>
        <xsl:text>;</xsl:text>
</xsl:template>

<xsl:template match="ph:Element">
<xsl:text>Components.</xsl:text>
<xsl:value-of select="@type"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>
    <xsl:value-of select="@id"/>
    <xsl:apply-templates select="ph:Attribute"/>
    <xsl:text>;</xsl:text>
</xsl:template>

<xsl:template match="ph:Attribute">
<xsl:variable name="count">
<xsl:for-each select=".">
<xsl:if test="ph:AttributeField[@name='type' and @value='int']">
<xsl:value-of select="count(../ph:Attribute)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="position()&lt;$count">
<xsl:text> (</xsl:text>
<xsl:value-of select="ph:AttributeField[@name = 'name']/@value"/>
<xsl:text>=</xsl:text>
<xsl:value-of select="ph:AttributeField[@name = 'value']/@value"/>
<xsl:text>,</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> </xsl:text>
<xsl:value-of select="ph:AttributeField[@name = 'name']/@value"/>
<xsl:text>=</xsl:text>
<xsl:value-of select="ph:AttributeField[@name = 'value']/@value"/>
<xsl:text>)</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

  <xsl:template match="ph:Edge">
         <xsl:variable name="sourceid" select="@sourceid"/>
         <xsl:variable name="targetid" select="@targetid"/>
        <xsl:variable name="SourceElement" select="//ph:Element[ph:Port[@id = $sourceid]]"/>
        <xsl:variable name="TargetElement" select="//ph:Element[ph:Port[@id = $targetid]]"/>
         <xsl:variable name="SourcePort" select="../ph:Element/ph:Port[@id = $sourceid]"/>
         <xsl:variable name="TargetPort" select="../ph:Element/ph:Port[@id = $targetid]"/>
         <xsl:text> connect(</xsl:text>
         <xsl:value-of select="translate($SourceElement/@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
         <xsl:value-of select="$SourceElement/@id" />
         <xsl:text>.</xsl:text>
         <xsl:value-of select="$SourcePort/ph:Attribute/ph:AttributeField[@name = 'value']/@value" />
         <xsl:text>,</xsl:text>
         <xsl:value-of select="translate($TargetElement/@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
         <xsl:value-of select="$TargetElement/@id" />
         <xsl:text>.</xsl:text>
         <xsl:value-of select="$TargetPort/ph:Attribute/ph:AttributeField[@name = 'value']/@value" />
         <xsl:text >);</xsl:text>
     </xsl:template>
</xsl:stylesheet>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.