我的XSLT以错误的方式将我的嵌套列表分组。期望的输出如下。它将所有hanging_indents分组为两个ref-list。请帮忙。我下面的代码大部分都在下面。我的代码主要在下面。我的代码主要在下面。
<document>
<head1>Heading 1</head1>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
<head1>Heading 2</head1>
<body_text>foo text</body_text>
<head1>Bibliography</head1>
<bib_head>Books</bib_head>
<hanging_indent>book citation 1</hanging_indent>
<hanging_indent>book citation 2</hanging_indent>
<bib_head>Periodicals</bib_head>
<hanging_indent>per citation 1</hanging_indent>
<hanging_indent>per citation 2</hanging_indent>
</document>
<document>
<head1>Heading 1</head1>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
<head1>Heading 2</head1>
<body_text>foo text</body_text>
<head1>Bibliography</head1>
<hanging_indent>book citation 1</hanging_indent>
<hanging_indent>book citation 2</hanging_indent>
<hanging_indent>per citation 1</hanging_indent>
<hanging_indent>per citation 2</hanging_indent>
</document>
<xsl:template match="head1">
<xsl:variable name="head1" select="." />
<xsl:if test="name(following-sibling::*[1])='body_text'">
<sec sec-type="bodytext" indexed="true">
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="following-sibling::body_text[preceding-sibling::head1[1] = $head1]" />
</sec>
</xsl:if>
<xsl:if test="name(following-sibling::*[1])='hanging_indent'">
<sec sec-type="hangindent" indexed="true">
<title><xsl:value-of select="."/></title>
<ref-list>
<xsl:apply-templates select="following-sibling::hanging_indent[preceding-sibling::head1[1] = $head1]" />
</ref-list>
</sec>
</xsl:if>
<xsl:if test="name(following-sibling::*[1])='bib_head'">
<sec sec-type="hangindent" indexed="true">
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="following-sibling::bib_head"/>
</sec>
</xsl:if>
</xsl:template><xsl:template match="hanging_indent">
<ref>
<citation>
<xsl:apply-templates select="node()"/>
</citation>
</ref>
</xsl:template><xsl:template match="bib_head">
<ref-list>
<title>
<xsl:apply-templates select="node()"/>
</title>
<xsl:apply-templates select="following-sibling::hanging_indent"/>
</ref-list>
</xsl:template>
<sec sec-type="bodytext" indexed="true">
<title>Heading 1</title>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
</sec>
<sec sec-type="bodytext" indexed="true">
<title>Heading 2</title>
<body_text>foo text</body_text>
</sec>
<sec sec-type="hangindent" indexed="true">
<title>Bibliography</title>
<ref-list>
<title>Books</title>
<ref><citation>book citation 1</citation></ref>
<ref><citation>book citation 2</citation></ref>
</ref-list>
<ref-list>
<title>Periodicals</title>
<ref><citation>per citation 1</citation></ref>
<ref><citation>per citation 2</citation></ref>
</ref-list>
</sec>
答案 0 :(得分:0)
也许试试:
hanging_indent
的生成ID对bib_head
个元素进行分组。bib_head
的生成ID对head1
个元素进行分组。body_text
的生成ID对head1
个元素进行分组。hanging_indent
的生成ID对head1
个元素进行分组。 (如果没有bib_head
元素,则使用。)场景#1 XML输入(缩进更改以减少有关嵌套的混淆)
<document>
<head1>Heading 1</head1>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
<head1>Heading 2</head1>
<body_text>foo text</body_text>
<head1>Bibliography</head1>
<bib_head>Books</bib_head>
<hanging_indent>book citation 1</hanging_indent>
<hanging_indent>book citation 2</hanging_indent>
<bib_head>Periodicals</bib_head>
<hanging_indent>per citation 1</hanging_indent>
<hanging_indent>per citation 2</hanging_indent>
</document>
场景#2 XML输入(无bib_head)(缩进更改以减少有关嵌套的混淆)
<document>
<head1>Heading 1</head1>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
<head1>Heading 2</head1>
<body_text>foo text</body_text>
<head1>Bibliography</head1>
<hanging_indent>book citation 1</hanging_indent>
<hanging_indent>book citation 2</hanging_indent>
<hanging_indent>per citation 1</hanging_indent>
<hanging_indent>per citation 2</hanging_indent>
</document>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!--Group hanging_indent by first preceding sibling bib_head.-->
<xsl:key name="hi-by-bh"
match="hanging_indent"
use="generate-id(preceding-sibling::bib_head[1])"/>
<!--Group bib_head by first preceding head1.-->
<xsl:key name="bh-by-h1"
match="bib_head"
use="generate-id(preceding-sibling::head1[1])"/>
<!--Group body_text by first preceding head1.-->
<xsl:key name="bt-by-h1"
match="body_text"
use="generate-id(preceding-sibling::head1[1])"/>
<!--Group hanging_indent by first preceding head1.-->
<xsl:key name="hi-by-h1"
match="hanging_indent"
use="generate-id(preceding-sibling::head1[1])"/>
<xsl:template match="/*">
<xsl:apply-templates select="head1"/>
</xsl:template>
<xsl:template match="head1[following-sibling::*[1][self::body_text]]">
<sec sec-type="bodytext" indexed="true">
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="key('bt-by-h1',generate-id())"/>
</sec>
</xsl:template>
<xsl:template match="head1[following-sibling::*[1][self::bib_head]]">
<sec sec-type="hangindent" indexed="true">
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="key('bh-by-h1',generate-id())"/>
</sec>
</xsl:template>
<xsl:template match="head1[following-sibling::*[1][self::hanging_indent]]">
<sec sec-type="hangindent" indexed="true">
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="key('hi-by-h1',generate-id())"/>
</sec>
</xsl:template>
<xsl:template match="bib_head">
<ref-list>
<title><xsl:value-of select="."/></title>
<xsl:apply-templates select="key('hi-by-bh',generate-id())"/>
</ref-list>
</xsl:template>
<xsl:template match="hanging_indent">
<ref><citation><xsl:value-of select="."/></citation></ref>
</xsl:template>
<xsl:template match="body_text">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
输出方案#1
<sec sec-type="bodytext" indexed="true">
<title>Heading 1</title>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
</sec>
<sec sec-type="bodytext" indexed="true">
<title>Heading 2</title>
<body_text>foo text</body_text>
</sec>
<sec sec-type="hangindent" indexed="true">
<title>Bibliography</title>
<ref-list>
<title>Books</title>
<ref>
<citation>book citation 1</citation>
</ref>
<ref>
<citation>book citation 2</citation>
</ref>
</ref-list>
<ref-list>
<title>Periodicals</title>
<ref>
<citation>per citation 1</citation>
</ref>
<ref>
<citation>per citation 2</citation>
</ref>
</ref-list>
</sec>
输出方案#2
<sec sec-type="bodytext" indexed="true">
<title>Heading 1</title>
<body_text>foo text</body_text>
<body_text>foo text</body_text>
</sec>
<sec sec-type="bodytext" indexed="true">
<title>Heading 2</title>
<body_text>foo text</body_text>
</sec>
<sec sec-type="hangindent" indexed="true">
<title>Bibliography</title>
<ref>
<citation>book citation 1</citation>
</ref>
<ref>
<citation>book citation 2</citation>
</ref>
<ref>
<citation>per citation 1</citation>
</ref>
<ref>
<citation>per citation 2</citation>
</ref>
</sec>
答案 1 :(得分:0)
由于您没有指定XSLT版本,我选择版本2.0, 它提供了一种简单而自然的分组元素的方法。
任务归结为2个嵌入式for-each-group
循环。
外部循环从head1
元素开始创建每个组
和内循环从bib_head
开始。
以下是您可以使用的脚本:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="document">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="head1">
<xsl:variable name="type">
<xsl:choose>
<xsl:when test="current-group()[2][name()='body_text']">
<xsl:text>bodytext</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>hangindent</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="group" select="current-group()"/>
<xsl:element name="sec">
<xsl:attribute name="sec-type" select="$type"/>
<xsl:attribute name="indexed" select="'true'"/>
<title>
<xsl:value-of select="$group[name()='head1']"/>
</title>
<xsl:choose>
<xsl:when test="$type='bodytext'">
<xsl:copy-of select="$group[name()='body_text']"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="BibHead">
<xsl:with-param name="group" select="subsequence($group, 2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<!-- Generate ref-list elements -->
<!-- group - source group without head1 -->
<xsl:template name="BibHead">
<xsl:param name="group"/>
<xsl:for-each-group select="$group" group-starting-with="bib_head">
<ref-list>
<title><xsl:value-of select="current-group()[name()='bib_head']"/></title>
<xsl:for-each select="subsequence(current-group(), 2)">
<ref><citation><xsl:value-of select="."/></citation></ref>
</xsl:for-each>
</ref-list>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
答案 2 :(得分:0)
假设XSLT 2.0或3.0你可以简单地嵌套两个xsl:for-each-group group-starting-with
,所以使用Saxon 9.8或当前的Altova你可以使用
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:param name="STREAMABLE" static="yes" as="xs:boolean" select="true()"/>
<xsl:mode _streamable="{$STREAMABLE}" on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="document">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="head1">
<sec sec-type="body-text" indexed="true">
<xsl:for-each-group select="current-group()" group-starting-with="bib_head">
<xsl:choose>
<xsl:when test="self::bib_head">
<ref-list>
<xsl:apply-templates select="current-group()"/>
</ref-list>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</sec>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="head1 | bib_head">
<title>
<xsl:apply-templates/>
</title>
</xsl:template>
<xsl:template match="hanging_indent">
<ref>
<citation>
<xsl:apply-templates/>
</citation>
</ref>
</xsl:template>
</xsl:stylesheet>
使用XSLT 2.0只需删除
<xsl:param name="STREAMABLE" static="yes" as="xs:boolean" select="true()"/>
并替换
<xsl:mode _streamable="{$STREAMABLE}" on-no-match="shallow-copy"/>
使用身份转换模板
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>