Xml XSLT-复杂的转换
我在XML片段的XSLT转换方面遇到了问题。源XML如下所示:Xml XSLT-复杂的转换,xml,xslt,Xml,Xslt,我在XML片段的XSLT转换方面遇到了问题。源XML如下所示: <XXX> <Name>Sample</Name> <MMM> <AAA ID="A"/> <MMM> <BBB ID="B"/> <MMM> <AA ID="C"/>
<XXX>
<Name>Sample</Name>
<MMM>
<AAA ID="A"/>
<MMM>
<BBB ID="B"/>
<MMM>
<AA ID="C"/>
<BB ID="D"/>
</MMM>
</MMM>
</MMM>
</XXX>
样品
但它需要转变为:
<XXX>
<Name>Sample</Name>
<MMM>
<MMM>
<MMM>
<AAA ID="A"/>
<BBB ID="B"/>
</MMM>
<AA ID="C"/>
</MMM>
<BB ID="D"/>
</MMM>
</XXX>
样品
规则很简单,MMM元素只能有两个子元素节点。如果这些节点中只有一个恰好是另一个MMM,则它需要占据第一个位置
使用代码很容易,但这些XML片段是SQL数据库中XML列的值,我想使用SQL和XSLT来更新这些值
任何指针或建议?解决此问题的一种方法是首先将
MMM
树和其他节点提取到单独的结构中,然后再次合并它们
这真是一个很好的挑战!让我熬夜到凌晨4点
以下XSLT(几乎!见下文)完成了这项工作:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" exclude-result-prefixes="exslt">
<xsl:output method="xml" encoding="ISO-8859-1" />
<!-- handling of MMM extraction -->
<xsl:template match="MMM" mode="extract_mmm">
<MMM>
<xsl:apply-templates mode="extract_mmm" />
</MMM>
</xsl:template>
<xsl:template match="*" mode="extract_mmm" />
<!-- handling of extraction of other nodes -->
<xsl:template match="MMM" mode="extract_other">
<xsl:apply-templates mode="extract_other" />
</xsl:template>
<xsl:template match="*" mode="extract_other">
<xsl:copy-of select="." />
</xsl:template>
<!-- handling of merging the two partial result sets -->
<xsl:template match="MMM" mode="dump">
<xsl:param name="others" />
<xsl:choose>
<!-- this handles the case of an MMM being a leaf node -->
<xsl:when test="count(MMM) = 0">
<xsl:variable name="nodes_in_next_sibling" select="2*count(following-sibling::MMM)" />
<MMM>
<xsl:copy-of select="$others[count($others) - $nodes_in_next_sibling - 1]" />
<xsl:copy-of select="$others[count($others) - $nodes_in_next_sibling]" />
</MMM>
</xsl:when>
<!-- this handles the case of an inner MMM with a sibling -->
<xsl:when test="count(../MMM) = 2">
<xsl:variable name="free_positions_in_second_child" select="count(MMM[position() = 2 and count(MMM) = 0])*2 + count(MMM[2]//MMM[count(MMM) = 0])*2 + count(MMM[position() = 2 and count(MMM) = 1]) + count(MMM[2]//MMM[count(MMM) = 1])" />
<MMM>
<xsl:apply-templates mode="dump" select="MMM[1]">
<xsl:with-param name="others" select="$others[position() < count($others)- $free_positions_in_second_child + 1]" />
</xsl:apply-templates>
<xsl:apply-templates mode="dump" select="MMM[2]">
<xsl:with-param name="others" select="$others[position() >= count($others) - $free_positions_in_second_child + 1]" />
</xsl:apply-templates>
</MMM>
</xsl:when>
<!-- this handles the case of an inner MMM without sibling -->
<xsl:when test="count(../MMM) = 1">
<MMM>
<xsl:apply-templates mode="dump">
<xsl:with-param name="others" select="$others[position() < count($others)]" />
</xsl:apply-templates>
</MMM>
<xsl:copy-of select="$others[position() = count($others)]" />
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="XXX">
<XXX>
<xsl:copy-of select="Name" />
<xsl:variable name="mmm_structure">
<xsl:apply-templates mode="extract_mmm" select="MMM" />
</xsl:variable>
<xsl:variable name="other_structure_tmp">
<xsl:apply-templates mode="extract_other" select="MMM" />
</xsl:variable>
<!-- http://stackoverflow.com/questions/4610921/how-to-concatenate-two-node-sets-such-that-order-is-respected -->
<!-- http://www.exslt.org/exsl/ -->
<xsl:variable name="other_structure" select="exslt:node-set($other_structure_tmp/*)" />
<xsl:apply-templates select="$mmm_structure" mode="dump">
<xsl:with-param name="others" select="$other_structure" />
</xsl:apply-templates>
</XXX>
</xsl:template>
</xsl:stylesheet>
如果这是一个问题,请告诉我。您定义规则的方式没有反映在输出XML中。我如何理解您的规则它看起来像:
Sample
True,但生成的XML是预期目标,AAA&BBB应该像第一个一样保留其遍历顺序。您不仅在切换节点,你也在将他们转移到更低或更高的级别,比如AAA从2级转移到4级,AA从4级转移到3级。。。为了安全起见,这就是困扰我的问题:XSLT2.0可以吗?还有一件事:我们可以假设树的深度总是单调地增加,然后又减少吗?或者可以存在具有两个非空MMM
节点作为子节点的MMM
节点吗?XSLT中的一些count
表达式可以简化。看,我刚刚注意到我的第三个音符(见上文)确实需要注意,因为我留下了一个不应该存在的空白(在结束MMM
之后,在B
和C
之间的MMM
将不得不研究这一点……尽管由于架构的变化,我不得不放弃这种方法,但我将保持该项目开放一段时间,因为这似乎是一个很好的挑战,提供了所有需要学习的内容。我稍后也将发布我的尝试。谢谢您的输入!
<?xml version="1.0" encoding="ISO-8859-1"?>
<XXX>
<Name>Sample</Name>
<MMM>
<MMM>
<MMM>
<AAA ID="A"/>
<AAA ID="B"/>
</MMM>
</MMM>
<BBB ID="C"/>
</MMM>
<BBB ID="D"/>
</XXX>