Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.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_Xpath_Xslt 1.0 - Fatal编程技术网

Xml 复制和添加具有多个子节点的父节点

Xml 复制和添加具有多个子节点的父节点,xml,xslt,xpath,xslt-1.0,Xml,Xslt,Xpath,Xslt 1.0,我在上一篇文章中犯了一个错误 我有这样的XML数据(这只是一个示例,章节和页面的数量都是可变的) 我正试图把它重现成这样 <books> <book> <chapter></chapter> <page></page> <page></page> <page></page> </book> <book> <chapte

我在上一篇文章中犯了一个错误

我有这样的XML数据(这只是一个示例,章节和页面的数量都是可变的)


我正试图把它重现成这样

<books>
 <book>
  <chapter></chapter>
  <page></page>
  <page></page>
  <page></page>
 </book>
 <book>
  <chapter></chapter>
  <page></page>
  <page></page>
 </book>
 <book>
  <chapter></chapter>
  <page></page>
  <page></page>
  <page></page>
  <page></page>
 </book>
</books>


据我所知,在新的篇章出现之前,没有办法将循环放入循环中。

尝试以下方法:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <books>
            <xsl:for-each select="books/chapter">
                <!-- for each chapter node, record the number of preceding sibling,
                     for the first chapter there is none, so that is why I added +1,
                     so when I count all the preceding sibling chapter of page, I will
                     get a match -->
                <xsl:variable name="chapter_count" select="count(preceding-sibling::chapter) + 1"/>
                <book>
                    <xsl:copy-of select="."/>
                    <!-- This code will ensure that the following sibling pages that
                         will be copied has the same number of preceding sibling
                         chapter (for pages, notice that I did not add 1 in the
                         predicate). So for the first chapter node, $chapter_count is 1
                         and the number of preceding sibling chapters at page node is 1,
                         thus the match -->
                    <xsl:copy-of select="following-sibling::page[count(preceding-sibling::chapter) = $chapter_count]"/>
                </book>
            </xsl:for-each>
        </books>
    </xsl:template>

</xsl:stylesheet>
<xsl:template match="books">
    <books>
        <xsl:apply-templates select="chapter"/>
    </books>
</xsl:template>

<xsl:template match="chapter">
    <xsl:variable name="this" select="generate-id()"/>
    <book>
        <xsl:copy-of select="."/>
        <xsl:copy-of 
            select="following-sibling::page[generate-id(preceding-sibling::chapter[1]) = $this]"/>
    </book>
</xsl:template>

@JoelMLamsen的想法是正确的,他的解决方案可以很好地工作,但可以简化一点,不使用计数。我们将尝试直接表示

对于每一章,处理其前一章为本章的以下页面

我们可以这样做:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <books>
            <xsl:for-each select="books/chapter">
                <!-- for each chapter node, record the number of preceding sibling,
                     for the first chapter there is none, so that is why I added +1,
                     so when I count all the preceding sibling chapter of page, I will
                     get a match -->
                <xsl:variable name="chapter_count" select="count(preceding-sibling::chapter) + 1"/>
                <book>
                    <xsl:copy-of select="."/>
                    <!-- This code will ensure that the following sibling pages that
                         will be copied has the same number of preceding sibling
                         chapter (for pages, notice that I did not add 1 in the
                         predicate). So for the first chapter node, $chapter_count is 1
                         and the number of preceding sibling chapters at page node is 1,
                         thus the match -->
                    <xsl:copy-of select="following-sibling::page[count(preceding-sibling::chapter) = $chapter_count]"/>
                </book>
            </xsl:for-each>
        </books>
    </xsl:template>

</xsl:stylesheet>
<xsl:template match="books">
    <books>
        <xsl:apply-templates select="chapter"/>
    </books>
</xsl:template>

<xsl:template match="chapter">
    <xsl:variable name="this" select="generate-id()"/>
    <book>
        <xsl:copy-of select="."/>
        <xsl:copy-of 
            select="following-sibling::page[generate-id(preceding-sibling::chapter[1]) = $this]"/>
    </book>
</xsl:template>
对于XSLT新手,有几点注意:

  • 我们记得
    此变量中当前章节的唯一id。或者,我们可以在
    []
    条件中使用
    生成id(current())

  • 前面的同级
    轴以与文档相反的顺序返回结果,因此
    [1]
    元素是前面的元素

  • 这不是使用
    为每个
    循环根模板中的章节,而是使用
    书籍
    章节
    的模板,有人可能会说这是更惯用的XSLT。默认根模板将负责调用
    books
    模板


  • 我相信简单有效的(!)方法是使用键:

    <?xml version="1.0" encoding="UTF-8"?>
    <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:key name="page-by-chapter" match="page" use="generate-id(preceding-sibling::chapter[1])" />
    
    <xsl:template match="/">
        <books>
            <xsl:for-each select="books/chapter">
                <book>
                    <xsl:copy-of select=". | key('page-by-chapter', generate-id())"/>
                </book>
            </xsl:for-each>
        </books>
    </xsl:template>
    
    </xsl:stylesheet>
    
    
    
    谢谢,我有这个工作:)。你能解释一下这句话吗:我在回答中添加了评论,我希望这就足够了。如果这个答案有帮助,请勾选左边的复选标记(使其显示为绿色)。这样,其他用户就可以知道这是公认的答案。你显然还没有测试过这个。在XPath中,没有
    [0]
    元素。节点编号从1开始。-2.“我们需要记住
    这个
    变量中的当前章节…”不,我们没有。这正是current()函数的作用3.表达式
    前面的同级::chapter[1]=$this
    并不意味着前面的章节与“当前”章节是同一节点;这意味着两个节点的值是相同的(这可能是巧合)。谢谢,抱歉。已修复,现在已测试。如果我还缺什么,一定要告诉我。你确定这就是它的工作原理:每一章都有自己的书吗?