Xml 复制和添加具有多个子节点的父节点
我在上一篇文章中犯了一个错误 我有这样的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
我正试图把它重现成这样
<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
并不意味着前面的章节与“当前”章节是同一节点;这意味着两个节点的值是相同的(这可能是巧合)。谢谢,抱歉。已修复,现在已测试。如果我还缺什么,一定要告诉我。你确定这就是它的工作原理:每一章都有自己的书吗?