xsl - 基于2个节点之间的属性对节点进行分组

时间:2011-04-09 21:56:22

标签: xml xslt xslt-1.0

在XSL 1.0中,我有一个搜索,并找到了类似的分组项目,但我认为这略有不同。 道歉,如果这已经被覆盖,我无法找到答案

输入

<?xml version="1.0"?>
<xmldoc>
<section paragraphMarker="true">Part 1. </section>
<section paragraphMarker="false">Part 2. </section>
<section paragraphMarker="false">Part 3. </section>
<section paragraphMarker="true">Part 4. </section>
<section paragraphMarker="true">Part 5. </section>
<section paragraphMarker="false">Part 6. </section>
</xmldoc>

所需输出

<p>Part 1. Part 2. Part 3.</p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

我尝试过以下方法: -

<xsl:key name="sectionsWithParagraphMarker" 
    match="section[@paragraphMarker='true']" use="."/>

<xsl:template match="/">
<xsl:for-each select=
    "/xmldoc/section[generate-id()
         = 
    generate-id(key('sectionsWithParagraphMarker',.)[1])]">
   <p>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="./following-sibling::node()
         [count(. | /xmldoc/section[@paragraphMarker='true'][1]/
             preceding-sibling::node())
         =
         count(/xmldoc/section[@paragraphMarker='true'][1]/
             preceding-sibling::node())
         ]"/>  
        </p>
    </xsl:for-each>
</xsl:template>

<xsl:template match="section">
    <xsl:select value-of="."/>
</xsl:template>

这不起作用,我一直坚持下去。它为所有组选择了太多“节”节点。感谢任何帮助!

3 个答案:

答案 0 :(得分:4)

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="section">
        <xsl:if test="@paragraphMarker='true'">
            <p>
                <xsl:apply-templates select="." mode="text" />
            </p>
        </xsl:if>
    </xsl:template>

    <xsl:template match="section" mode="text">
        <xsl:value-of select="." />
        <xsl:apply-templates select="following-sibling::section[1][@paragraphMarker='false']" mode="text" />
    </xsl:template>
</xsl:stylesheet>

由于此代码仅向前看,因此它比执行回溯的解决方案更有效(在许多实现中向后移动的XPath轴很慢)。

答案 1 :(得分:2)

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kSectsByPara"
  match="section[not(@paragraphMarker='true')]"
  use="generate-id(preceding-sibling::*
                    [@paragraphMarker='true']
                    [1]
                   )"
 />

 <xsl:template match="*[@paragraphMarker='true']">
  <p>
   <xsl:copy-of select=
    "text()|key('kSectsByPara', generate-id())/text()"/>
  </p>
 </xsl:template>

 <xsl:template match="*/*[not(@paragraphMarker='true')]"/>
</xsl:stylesheet>

应用于提供的XML文档

<xmldoc>
    <section paragraphMarker="true">Part 1. </section>
    <section paragraphMarker="false">Part 2. </section>
    <section paragraphMarker="false">Part 3. </section>
    <section paragraphMarker="true">Part 4. </section>
    <section paragraphMarker="true">Part 5. </section>
    <section paragraphMarker="false">Part 6. </section>
</xmldoc>

生成想要的正确结果

<p>Part 1. Part 2. Part 3. </p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

<强>解释

名为“kSectsByPara”的<xsl:key>定义了generate-id()section属性paragraphMarker="true"与后续section元素组之间的映射他们的属性paragraphMarker="false"

答案 2 :(得分:1)

以下样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="section[@paragraphMarker='true']">
        <p>
            <xsl:apply-templates
               select=".|following-sibling::section[not(@paragraphMarker='true')]
           [preceding-sibling::section[@paragraphMarker='true'][1]=current()]" 
               mode="inner"/>
        </p>
    </xsl:template>
    <xsl:template match="section" />
</xsl:stylesheet>

产生所需的输出:

<p>Part 1. Part 2. Part 3. </p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

在英语中,我们选择以下所有不是段落标记的兄弟姐妹,其 段落标记的第一个兄弟姐妹是当前标记。请注意,这需要我们遍历所有以下兄弟,然后回溯以查找前一个标记(在每种情况下)。