我有一个像这样的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不会按顺序处理。 如果有人可以解释这个问题的解决方案,将会非常有帮助。
感谢。
答案 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>