Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT-复杂的转换_Xml_Xslt - Fatal编程技术网

Xml XSLT-复杂的转换

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

我在XML片段的XSLT转换方面遇到了问题。源XML如下所示:

<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() &lt; 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() &gt;= 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() &lt; 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>