Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.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 需要一种优雅的方式将兄弟姐妹移动到基于属性值的层次结构中_Xml_Xslt_Xml Parsing_Xslt 1.0 - Fatal编程技术网

Xml 需要一种优雅的方式将兄弟姐妹移动到基于属性值的层次结构中

Xml 需要一种优雅的方式将兄弟姐妹移动到基于属性值的层次结构中,xml,xslt,xml-parsing,xslt-1.0,Xml,Xslt,Xml Parsing,Xslt 1.0,我需要一种优雅的方法,根据属性值将兄弟姐妹分组为孩子。这类似于基于“colspan”属性将html表转换为层次数据 输入结构有多个同级节点,子节点包含数据。然而,数据节点可包含指示层级优越性的层级属性 输入 <root> <Sibling> <Data level="4">ABC</Data> </Sibling> <Sibling> <Data level="3">fff</D

我需要一种优雅的方法,根据属性值将兄弟姐妹分组为孩子。这类似于基于“colspan”属性将html表转换为层次数据

输入结构有多个同级节点,子节点包含数据。然而,数据节点可包含指示层级优越性的层级属性

输入

<root>
  <Sibling>
    <Data level="4">ABC</Data>
  </Sibling>
  <Sibling>
    <Data level="3">fff</Data>
  </Sibling>
  <Sibling>
    <Data>8000</Data>
    <Data>01/04/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="3">ggg</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/05/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">DEF</Data>
  </Sibling>
  <Sibling>
    <Data level="3">iii</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/22/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">GHI</Data>
  </Sibling>
  <Sibling>
    <Data level="3">mmm</Data>
  </Sibling>
  <Sibling>
    <Data>4000</Data>
    <Data>07/05/2011</Data>
  </Sibling>
  <Sibling>
    <Data level="3">nnn</Data>
  </Sibling>
  <Sibling>
    <Data>6000</Data>
    <Data>01/07/2011</Data>
  </Sibling>
</root>
<Main>
  <Group>
    <Data level="4">ABC</Data>
    <Subgroup>
      <Data level="3">fff</Data>
      <Child>
        <Data>8000</Data>
        <Data>01/04/2013</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">ggg</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/05/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">DEF</Data>
    <Subgroup>
      <Data level="3">iii</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/22/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">GHI</Data>
    <Subgroup>
      <Data level="3">mmm</Data>
      <Child>
        <Data>4000</Data>
        <Data>07/05/2011</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">nnn</Data>
      <Child>
        <Data>6000</Data>
        <Data>01/07/2011</Data>
      </Child>
    </Subgroup>
  </Group>
</Main>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml"  indent="yes" omit-xml-declaration="yes" />

  <xsl:variable name="group_begin">&lt;Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_begin">&lt;Subgroup&gt;</xsl:variable>
  <xsl:variable name="group_end">&lt;/Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_end">&lt;/Subgroup&gt;</xsl:variable>

  <xsl:template match="/">
    <Main>
      <xsl:apply-templates select="root" />
    </Main>
  </xsl:template>

  <xsl:template match="root">
    <xsl:for-each select="Sibling">
      <xsl:choose>
        <xsl:when test="Data[not(@level)]">
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="0"/>
            <xsl:with-param name="next_level" select="following-sibling::*[1]/Data/@level"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="Data/@level"/>
            <xsl:with-param name="next_level" select="0"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
  </xsl:template>

  <xsl:template name="Sibling">
    <xsl:param name="level"  />
    <xsl:param name="next_level"/>
    <xsl:choose>
      <xsl:when test="$level = '4'">
        <xsl:value-of disable-output-escaping="yes" select="$group_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:when test="$level = '3'">
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:otherwise>
        <Child>
        <xsl:copy-of select="*"/>
        </Child>
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_end"/>
        <xsl:if test="$next_level = 4">
          <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

基础知识
fff
8000
01/04/2013
ggg
2000
01/05/2013
DEF
三,
2000
01/22/2013
GHI
嗯
4000
07/05/2011
nnn
6000
01/07/2011
使用level属性,我需要移动兄弟姐妹以成为子对象,如下所示

输出

<root>
  <Sibling>
    <Data level="4">ABC</Data>
  </Sibling>
  <Sibling>
    <Data level="3">fff</Data>
  </Sibling>
  <Sibling>
    <Data>8000</Data>
    <Data>01/04/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="3">ggg</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/05/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">DEF</Data>
  </Sibling>
  <Sibling>
    <Data level="3">iii</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/22/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">GHI</Data>
  </Sibling>
  <Sibling>
    <Data level="3">mmm</Data>
  </Sibling>
  <Sibling>
    <Data>4000</Data>
    <Data>07/05/2011</Data>
  </Sibling>
  <Sibling>
    <Data level="3">nnn</Data>
  </Sibling>
  <Sibling>
    <Data>6000</Data>
    <Data>01/07/2011</Data>
  </Sibling>
</root>
<Main>
  <Group>
    <Data level="4">ABC</Data>
    <Subgroup>
      <Data level="3">fff</Data>
      <Child>
        <Data>8000</Data>
        <Data>01/04/2013</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">ggg</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/05/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">DEF</Data>
    <Subgroup>
      <Data level="3">iii</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/22/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">GHI</Data>
    <Subgroup>
      <Data level="3">mmm</Data>
      <Child>
        <Data>4000</Data>
        <Data>07/05/2011</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">nnn</Data>
      <Child>
        <Data>6000</Data>
        <Data>01/07/2011</Data>
      </Child>
    </Subgroup>
  </Group>
</Main>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml"  indent="yes" omit-xml-declaration="yes" />

  <xsl:variable name="group_begin">&lt;Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_begin">&lt;Subgroup&gt;</xsl:variable>
  <xsl:variable name="group_end">&lt;/Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_end">&lt;/Subgroup&gt;</xsl:variable>

  <xsl:template match="/">
    <Main>
      <xsl:apply-templates select="root" />
    </Main>
  </xsl:template>

  <xsl:template match="root">
    <xsl:for-each select="Sibling">
      <xsl:choose>
        <xsl:when test="Data[not(@level)]">
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="0"/>
            <xsl:with-param name="next_level" select="following-sibling::*[1]/Data/@level"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="Data/@level"/>
            <xsl:with-param name="next_level" select="0"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
  </xsl:template>

  <xsl:template name="Sibling">
    <xsl:param name="level"  />
    <xsl:param name="next_level"/>
    <xsl:choose>
      <xsl:when test="$level = '4'">
        <xsl:value-of disable-output-escaping="yes" select="$group_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:when test="$level = '3'">
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:otherwise>
        <Child>
        <xsl:copy-of select="*"/>
        </Child>
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_end"/>
        <xsl:if test="$next_level = 4">
          <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

基础知识
fff
8000
01/04/2013
ggg
2000
01/05/2013
DEF
三,
2000
01/22/2013
GHI
嗯
4000
07/05/2011
nnn
6000
01/07/2011
我开发的样式表不是很优雅,并且对级别值进行了假设。它通过输出基于逻辑和级别值的打开和关闭标记来创建父节点。我更喜欢传递节点和添加子节点,但找不到这样做的示例。有没有人有更优雅的方法

样式表

<root>
  <Sibling>
    <Data level="4">ABC</Data>
  </Sibling>
  <Sibling>
    <Data level="3">fff</Data>
  </Sibling>
  <Sibling>
    <Data>8000</Data>
    <Data>01/04/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="3">ggg</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/05/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">DEF</Data>
  </Sibling>
  <Sibling>
    <Data level="3">iii</Data>
  </Sibling>
  <Sibling>
    <Data>2000</Data>
    <Data>01/22/2013</Data>
  </Sibling>
  <Sibling>
    <Data level="4">GHI</Data>
  </Sibling>
  <Sibling>
    <Data level="3">mmm</Data>
  </Sibling>
  <Sibling>
    <Data>4000</Data>
    <Data>07/05/2011</Data>
  </Sibling>
  <Sibling>
    <Data level="3">nnn</Data>
  </Sibling>
  <Sibling>
    <Data>6000</Data>
    <Data>01/07/2011</Data>
  </Sibling>
</root>
<Main>
  <Group>
    <Data level="4">ABC</Data>
    <Subgroup>
      <Data level="3">fff</Data>
      <Child>
        <Data>8000</Data>
        <Data>01/04/2013</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">ggg</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/05/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">DEF</Data>
    <Subgroup>
      <Data level="3">iii</Data>
      <Child>
        <Data>2000</Data>
        <Data>01/22/2013</Data>
      </Child>
    </Subgroup>
  </Group>
  <Group>
    <Data level="4">GHI</Data>
    <Subgroup>
      <Data level="3">mmm</Data>
      <Child>
        <Data>4000</Data>
        <Data>07/05/2011</Data>
      </Child>
    </Subgroup>
    <Subgroup>
      <Data level="3">nnn</Data>
      <Child>
        <Data>6000</Data>
        <Data>01/07/2011</Data>
      </Child>
    </Subgroup>
  </Group>
</Main>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml"  indent="yes" omit-xml-declaration="yes" />

  <xsl:variable name="group_begin">&lt;Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_begin">&lt;Subgroup&gt;</xsl:variable>
  <xsl:variable name="group_end">&lt;/Group&gt;</xsl:variable>
  <xsl:variable name="subgroup_end">&lt;/Subgroup&gt;</xsl:variable>

  <xsl:template match="/">
    <Main>
      <xsl:apply-templates select="root" />
    </Main>
  </xsl:template>

  <xsl:template match="root">
    <xsl:for-each select="Sibling">
      <xsl:choose>
        <xsl:when test="Data[not(@level)]">
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="0"/>
            <xsl:with-param name="next_level" select="following-sibling::*[1]/Data/@level"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="Sibling">
            <xsl:with-param name="level" select="Data/@level"/>
            <xsl:with-param name="next_level" select="0"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
  </xsl:template>

  <xsl:template name="Sibling">
    <xsl:param name="level"  />
    <xsl:param name="next_level"/>
    <xsl:choose>
      <xsl:when test="$level = '4'">
        <xsl:value-of disable-output-escaping="yes" select="$group_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:when test="$level = '3'">
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_begin"/>
        <xsl:copy-of select="*"/>
      </xsl:when>
      <xsl:otherwise>
        <Child>
        <xsl:copy-of select="*"/>
        </Child>
        <xsl:value-of disable-output-escaping="yes" select="$subgroup_end"/>
        <xsl:if test="$next_level = 4">
          <xsl:value-of disable-output-escaping="yes" select="$group_end"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

团体
子群
/团体
/子群

我在这里研究了使用该技术,但属性级别实际上是一个相对值,而不是固定值。

这里使用XSLT 2.0解决了一个类似的问题:


您真的需要XSLT1.0吗?这更难,但并非不可能。基本上,您需要掌握“同级递归”技术,其中特定节点的模板规则确实会将模板应用于紧随其后的同级节点。搜索“同级递归”可能会产生一些想法。

感谢您的快速响应。不幸的是,在python的lxml能够支持XSLT2.0之前,我一直坚持使用1.0。我现在使用的是“跟随同级”,但不能正确地得到正确的嵌套。是的,同级递归可能会很棘手,即使你已经习惯了。当你做对的时候,代码非常简单明了,但是要做到这一点可能很困难。