如果 - 然后在XSLT中

时间:2011-06-16 13:08:41

标签: xml xslt xslt-1.0

从XML文件中提取一些数据时遇到问题。如果有多个ph:Attribute,我仍然有问题要弄清楚如何处理ph:Element,但输出应该看起来像(s_rel0 = 5, par_s_rel0 = 5)而不是(s_rel0 = 5)(par_s_rel0 = 5)。也许是if-then case!?

第二个连接应该由flange_b而不是flange_a组成。我在搜索错误时却找不到它。

你知道我在哪里犯了错误!? 谢谢你的帮助。

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;

4 个答案:

答案 0 :(得分:7)

以下是xslt

中if-else的使用方法
<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>

答案 1 :(得分:3)

  
    

输出应该看起来像(s_rel0 = 5, par_s_rel0 = 5)

  

关于括号,只需在相关模板中添加/附加一些条件:

<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>
  
    

第二个连接应包含flange_b而不是flange_a

  

关于错误的连接,您需要在最后一个模板中更改两行,特别是那些选择值的行:

<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" />

这是因为:

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

您正在选择整个ph:Element节点,因此您需要在之后重新匹配。您的模板适用于第一次连接的事实只是一个案例。

答案 2 :(得分:2)

在我看来,一个好的XSLT代码没有if / else结构。 以下是仅基于模板覆盖的版本:

<?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>

顺便说一下......我添加了一个xsl:key元素来索引ph:与//ph:Element[ph:Port[@id = $sourceid]]相比可以节省处理时间的端口

答案 3 :(得分: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>