2010-01-29 31 views
17

我正在尝试编写XSLT,它将在选定的后续兄弟上运行for-each,但在到达另一个标记(h1)时停止。XSLT:选择以下兄弟直到达到指定的标记

这里的源XML:

<?xml version="1.0"?> 
<html> 
    <h1>Test</h1> 
    <p>Test: p 1</p> 
    <p>Test: p 2</p> 
    <h1>Test 2</h1> 
    <p>Test2: p 1</p> 
    <p>Test2: p 2</p> 
    <p>Test2: p 3</p> 
</html> 

这里的XSLT:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/"> 
     <content> 
      <xsl:apply-templates/> 
     </content> 
    </xsl:template> 

    <xsl:template match="h1"> 
     <section> 
      <sectionHeading> 
       <xsl:apply-templates/> 
      </sectionHeading> 
      <sectionContent> 
       <xsl:for-each select="following-sibling::p"> 
        <paragraph> 
         <xsl:value-of select="."/> 
        </paragraph> 
       </xsl:for-each> 
      </sectionContent> 
     </section> 
    </xsl:template> 

    <xsl:template match="p"/> 
</xsl:stylesheet> 

这里的当前结果:

<?xml version="1.0" encoding="UTF-8"?> 
<content> 
    <section> 
     <sectionHeading>Test</sectionHeading> 
     <sectionContent> 
      <paragraph>Test: p 1</paragraph> 
      <paragraph>Test: p 2</paragraph> 
      <paragraph>Test: p 3</paragraph> 
      <paragraph>Test2: p 1</paragraph> 
      <paragraph>Test2: p 2</paragraph> 
     </sectionContent> 
    </section> 
    <section> 
     <sectionHeading>Test 2</sectionHeading> 
     <sectionContent> 
      <paragraph>Test2: p 1</paragraph> 
      <paragraph>Test2: p 2</paragraph> 
     </sectionContent> 
    </section> 
</content> 

这里是预期的结果:

<?xml version="1.0" encoding="UTF-8"?> 
<content> 
<section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test: p 1</paragraph> 
     <paragraph>Test: p 2</paragraph> 
     <paragraph>Test: p 3</paragraph> 
    </sectionContent> 
</section> 
<section> 
    <sectionHeading>Test 2</sectionHeading> 
    <sectionContent> 
     <paragraph>Test2: p 1</paragraph> 
     <paragraph>Test2: p 2</paragraph> 
    </sectionContent> 
</section> 
</content> 
+0

@添,虽然我们可以得到XSLT一个解决方案,我宁愿建议你到XML格式更改为

测试

测试:第1页

测试:第2页

试验2

Test2的:p 1

Test2的:p 2

Test2:p 3

哪个更合理,可读性强,易于在xslt中查询。 – Ravisha 2010-01-30 04:05:16

回答

25

试试这个:(而不是要求所有p的,我们要求所有的P公司,其最近前面的H1是当前的)。

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/"> 
     <content> 
      <xsl:apply-templates/> 
     </content> 
    </xsl:template> 

    <xsl:template match="h1"> 
     <xsl:variable name="header" select="."/> 
     <section> 
      <sectionHeading> 
       <xsl:apply-templates/> 
      </sectionHeading> 
      <sectionContent> 
       <xsl:for-each select="following-sibling::p[preceding-sibling::h1[1] = $header]"> 
        <paragraph> 
         <xsl:value-of select="."/> 
        </paragraph> 
       </xsl:for-each> 
      </sectionContent> 
     </section> 
    </xsl:template> 

    <xsl:template match="p"/> 
</xsl:stylesheet> 
+0

刚刚测试过,它的工作完美。非常感谢你。 – Tim 2010-01-29 22:39:04

+0

如果有效,请接受解决方案。 – 2010-01-29 22:52:16

+0

接受的答案。 – Tim 2010-01-29 23:03:04

4

接受的答案有一个不好的副作用,它是有点不对。

此外,在这篇文章中,我将解释真正比较下列基本语句,以及为什么它可以失败。


重温/分析的情况,而在模板<xsl:template match="h1">是:

  • 当前上下文节点是匹配的<xsl:template>任何h1
  • 变量名称header包含我当前上下文节点的副本。

基本语句这是坏/错误:

以下同胞:: P [前同辈:: H1 [1] = $头]

  • 选择我的上下文节点|的所有后续兄弟姐妹pfollowing-sibling::p
  • 滤波器这些p其中第一(最接近)前同辈命名h1“是”相同可变$header | ...[preceding-sibling::h1[1] = $header]

!!在XSLT 1.0中,一个节点与一个节点的比较将通过它的值来完成!


在示例中查看。让我们假装输入XML是这样的[<h1>包含两次相同的值Test]:

<html> 
    <h1>Test</h1> 
    <p>Test: p 1</p> 
    <p>Test: p 2</p> 
    <h1>Test</h1> 
    <p>Test2: p 1</p> 
    <p>Test2: p 2</p> 
    <p>Test2: p 3</p> 
</html> 

一个错!结果将被创建:

<content> 
    <section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test: p 1</paragraph> 
     <paragraph>Test: p 2</paragraph> 
     <paragraph>Test2: p 1</paragraph> <-- should be only in 2. section 
     <paragraph>Test2: p 2</paragraph> <-- should be only in 2. section 
     <paragraph>Test2: p 3</paragraph> <-- should be only in 2. section 
    </sectionContent> 
    </section> 
    <section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test2: p 1</paragraph> 
     <paragraph>Test2: p 2</paragraph> 
     <paragraph>Test2: p 3</paragraph> 
    </sectionContent> 
    </section> 
</content> 

正确的比较

.... 
<xsl:variable name="header" select="generate-id(.)"/> 
.... 
<xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::h1[1]) = $header]"> 
.... 

使用功能generate-id()得到唯一的(至少在当前文档中)节点的ID,现在比较节点VS节点!即使您使用<xsl:key>这种技术,您也必须使用generate-id!

+0

为什么不编辑接受的解决方案并添加评论? – 2018-02-21 19:07:30