按顺序处理XSLT代码

时间:2016-08-15 06:59:58

标签: xml xslt xslt-1.0

我有一个像这样的xml:

 <bpmn:process id="Process_1" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL">
    <bpmn:exclusiveGateway id="ExclusiveGateway_03b639w" />
    <bpmn:startEvent id="StartEvent_0nmzsw0" />
    <bpmn:sendTask id="Task_13s9uob"/>
    <bpmn:userTask id="Task_1v0riz3" />
</bpmn:process>

我想将它转换为这个xml:

<process id="Process_1">
    <Gateway type="exclusive" id="ExclusiveGateway_03b639w" />
    <Event type="start" id="StartEvent_0nmzsw0" />
    <Task type="send" id="Task_13s9uob"/>
    <Task type="user" id="Task_1v0riz3" />
</process>

为此,我使用了两个XSLT 1.0代码:

1 - 删除命名空间

 <xsl:template match="*">
  <xsl:element name="{local-name()}">
    <xsl:for-each select="@*">
      <xsl:attribute name="{local-name()}">
        <xsl:value-of select="."/>
      </xsl:attribute>
    </xsl:for-each>
    <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

2分割节点名称和添加类型属性

<xsl:template match="process/*">
    <xsl:variable name="split" select="string-length(substring-before(translate(name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
    <xsl:element name="{substring(name(), $split + 1)}">
      <xsl:attribute name="type">
        <xsl:value-of select="substring(name(), 1, $split)"/>
      </xsl:attribute>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
</xsl:template>   

但是当我像这样一起使用它们时:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>          

    <!-- Step 1 -->    
    <xsl:template match="*">
      <xsl:element name="{local-name()}">
        <xsl:for-each select="@*">
          <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
          </xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates/>
      </xsl:element>
    </xsl:template>    

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

    <xsl:template match="process/*">
      <xsl:variable name="split" select="string-length(substring-before(translate(name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
      <xsl:element name="{substring(name(), $split + 1)}">
        <xsl:attribute name="type">
          <xsl:value-of select="substring(name(), 1, $split)"/>
        </xsl:attribute>
        <xsl:apply-templates select="@* | node()"/>
      </xsl:element>
    </xsl:template>

  </xsl:stylesheet>

结果,输入没有改变!。

在线链接:http://xsltransform.net/pPJ8LUR

我认为xslt不会按顺序处理。 如果有人可以解释这个问题的解决方案,将会非常有帮助。

感谢。

3 个答案:

答案 0 :(得分:1)

我怀疑你使它变得比它需要的更复杂。您所需要做的就是:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
exclude-result-prefixes="bpmn">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="/bpmn:process/*">
    <xsl:variable name="split" select="string-length(substring-before(translate(local-name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
    <xsl:element name="{substring(local-name(), $split + 1)}">
        <xsl:attribute name="type">
            <xsl:value-of select="substring(local-name(), 1, $split)"/>
        </xsl:attribute>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

或者也许只是(取决于您的实际输入与所示示例的不同之处):

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>   

<xsl:template match="/*/*">
    <xsl:variable name="split" select="string-length(substring-before(translate(local-name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
    <xsl:element name="{substring(local-name(), $split + 1)}">
        <xsl:attribute name="type">
            <xsl:value-of select="substring(local-name(), 1, $split)"/>
        </xsl:attribute>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

如果你知道的话,我会重复我的recommendation来明确地通过他们的名字来处理各个节点。

答案 1 :(得分:1)

当你说“xslt不按顺序处理”时,我认为你想说的是当两个模板规则匹配一个节点时,只应用其中一个。那是对的。

如果您希望一个模板规则处理另一个模板规则的输出,则必须在变量中捕获第一个模板规则的输出,然后将模板应用于变量,最好是以不同的模式,以避免混淆。 / p>

答案 2 :(得分:0)

首先,您在源XML中使用了名称空间bpmn。我在XSL中添加了一个bpmn命名空间。

其次,在您的第1步中,您匹配*,在第2步中,您匹配了node()node()匹配*text()comment()processing-instruction()。我修改了你的第2步。

第三,您应该使用local-name()模板匹配中的bpmn:process功能。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:bpmn="www.bpmn.com">

    <xsl:strip-space elements="*"/>
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>          

    <!-- Step 1 -->    
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:for-each select="@*">
                <xsl:attribute name="{local-name()}">
                    <xsl:value-of select="."/>
                </xsl:attribute>
            </xsl:for-each>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>    

    <!-- Step 2 -->
    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="bpmn:process/*">
        <xsl:variable name="split" select="string-length(substring-before(translate(local-name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
        <xsl:element name="{substring(local-name(), $split + 1)}">
            <xsl:attribute name="type">
                <xsl:value-of select="substring(local-name(), 1, $split)"/>
            </xsl:attribute>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>