为特定祖先的每个实例选择特定名称的第一个后代

时间:2014-09-30 21:54:53

标签: xml xslt xpath

我有一些复杂的MS-Office XML看起来就像你在链接中看到的那样,但是文档根目录的许多p:sldp:notes子项的完整源代码要长得多。始终显示在p:sldp:notesp:sldp:notes http://pastie.org/9604783

的订单中

感谢JLRishe,我有一些xsl提取后代a:t元素,并根据上下文将其内容包装在各种标签中。

XSL如下

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
  <xsl:output method="xml"/>

  <xsl:template match="/">
    <document>
      <xsl:apply-templates select="//a:t"/>
    </document>
  </xsl:template>

  <xsl:template match="a:t">
    <xsl:variable name="sldAncestor" select="ancestor::p:sld" />
    <xsl:variable name="notesAncestor" select="ancestor::p:notes" />
    <xsl:variable name="rAncestorPreLevel"
                  select="ancestor::a:r/preceding-sibling::*[1]/@lvl" />

    <xsl:variable name="wrapperName">
      <xsl:choose>

         <xsl:when test="$sldAncestor and $rAncestorPreLevel = '1'">
          <xsl:text>SlideBullet</xsl:text>
        </xsl:when>
        <xsl:when test="$sldAncestor and $rAncestorPreLevel = '2'">
          <xsl:text>SlideBullet1</xsl:text>
        </xsl:when>
        <xsl:when test="$sldAncestor and $rAncestorPreLevel = '3'">
          <xsl:text>SlideBullet2</xsl:text>
        </xsl:when>

        <xsl:when test="$notesAncestor and $rAncestorPreLevel = '0'"  >
          <xsl:text>StudentNotes</xsl:text>
        </xsl:when>

         <xsl:when test="$notesAncestor and $rAncestorPreLevel = '1'"  >
          <xsl:text>StudentNotes</xsl:text>
        </xsl:when>

        <xsl:when test="$notesAncestor and $rAncestorPreLevel = '2'">
          <xsl:text>Student_Notes_Bullet</xsl:text>
        </xsl:when>
        <xsl:when test="$notesAncestor and $rAncestorPreLevel = '3'">
          <xsl:text>Student_Notes_Bullet_1</xsl:text>
        </xsl:when>

        <xsl:otherwise>Body</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:element name="{$wrapperName}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

但我希望扩展一下,能够选择每个a:t内显示的第一个p:sld元素,并将其包含在代码<SlideTitleGhost></SlideTitleGhost>中。

同样,我希望能够在每个a:t元素中选择第一个p.notes元素 并使用标记<PageBreak /><StudentNotes></StudentNotes>

包装其内容

请注意,并非所有a:t元素都是兄弟元素。同级a:t元素是a:r元素的子元素,但每个a:rp:notes元素都有多个p:sld个元素。而且那些a:r元素也不可能是兄弟姐妹。每个a:t元素的xpath的最后一部分为//p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:t

我在Windows上使用Saxon-HE,但如果需要可以切换处理器。

所需的输出看起来像这样。

<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
    <SlideTitleGhost>header text</SlideTitleGhost>
    <Body>body text </Body>
    <Body>body text </Body>
    <Body>body text </Body>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet1>bulleted2 text</SlideBullet1>
    <SlideBullet1>bulleted2 text</SlideBullet1>
    <SlideBullet1>bulleted2 text</SlideBullet1>
    <SlideBullet1>bulleted2 text</SlideBullet1>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet>bulleted text</SlideBullet>
    <SlideBullet>bulleted text</SlideBullet>
    <Body>body text</Body>
    <Body>body text</Body>
    <Body>footer text</Body>
    <Body>10</Body>
    <Body>10</Body>
    <PageBreak />
    <StudentNotes>notes header text</StudentNotes>
    <Body>notes body text</Body>
    <StudentNotes>notes body text</StudentNotes>
    <StudentNotes>notes table header text</StudentNotes>
    <StudentNotes>notes table header text</StudentNotes>
    <StudentNotes>notes table body text</StudentNotes>
    <StudentNotes>table body text</StudentNotes>
    <StudentNotes>notes table body text</StudentNotes>
    <StudentNotes>notes table body text</StudentNotes>
    <StudentNotes>notes table body text</StudentNotes>
    <StudentNotes>notes table body text</StudentNotes>
</document>

1 个答案:

答案 0 :(得分:0)

我能够通过以下XSL得到足够接近期望的结果(并且去除每个p:sld下的最后一个a:t元素)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
  <xsl:output method="xml"/>

  <xsl:template match="/">
    <document>
      <xsl:apply-templates select="//a:t"/>
    </document>
  </xsl:template>

  <xsl:template match="a:t">
    <xsl:variable name="sldAncestor" select="ancestor::p:sld" />
    <xsl:variable name="notesAncestor" select="ancestor::p:notes" />
    <xsl:variable name="rAncestorPreLevel" select="ancestor::a:r/preceding-sibling::a:pPr/@lvl" />
    <xsl:variable name="SlideTitle" select="ancestor::p:txBody/preceding-sibling::p:nvSpPr/p:nvPr/p:ph/@type" />

    <xsl:variable name="wrapperName"> 

    <xsl:choose>
         <xsl:when test="$sldAncestor and $rAncestorPreLevel = '1'">
          <xsl:text>SlideBullet</xsl:text>
        </xsl:when>
        <xsl:when test="$sldAncestor and $rAncestorPreLevel = '2'">
          <xsl:text>SlideBullet1</xsl:text>
        </xsl:when>
        <xsl:when test="$sldAncestor and $rAncestorPreLevel = '3'">
          <xsl:text>SlideBullet2</xsl:text>
        </xsl:when>
        <xsl:when test="$sldAncestor and $SlideTitle = 'title'">
          <xsl:text>SlideTitleGhost</xsl:text>
        </xsl:when>

        <xsl:when test="$notesAncestor and not(ancestor::a:r/preceding-sibling::a:pPr/@lvl)">
          <xsl:text>StudentNotes</xsl:text>
        </xsl:when>

         <xsl:when test="$notesAncestor and $rAncestorPreLevel = '1'"  >
          <xsl:text>StudentNotes</xsl:text>
        </xsl:when>

        <xsl:when test="$notesAncestor and $rAncestorPreLevel = '2'">
          <xsl:text>Student_Notes_Bullet</xsl:text>
        </xsl:when>
        <xsl:when test="$notesAncestor and $rAncestorPreLevel = '3'">
          <xsl:text>Student_Notes_Bullet_1</xsl:text>
        </xsl:when>

        <xsl:otherwise>SlideTopic</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
       <xsl:when test="not($notesAncestor and ancestor::a:fld)">
           <xsl:element name="{$wrapperName}">
                      <xsl:value-of select="." />
           </xsl:element>
      </xsl:when>
       <xsl:when test="$notesAncestor and ancestor::a:fld">
        <xsl:element name="PageBreak"></xsl:element>
           </xsl:when>
</xsl:choose>

  </xsl:template>

</xsl:stylesheet>

我是通过确定每个a:t元素(p:sld)的每个第一个ancestor::p:txBody/preceding-sibling::p:nvSpPr/p:nvPr/p:ph/@type后代元素的唯一条件来实现的。第二个xsl:choose添加到底部让我扔掉每个a:t中的最后一个p:sld,我不想将其包含在输出中,因为它不需要输出,并将其作为在<pagebreak>的第一个a:t后代之前插入p:notes标记的时刻。

更新:事实证明这不是解决方案,因为文档顺序与源文件中文档在页面上从上到下显示的顺序不匹配很多页面。在许多情况下,显示在每张幻灯片顶部的标题文字在doc顺序中的其他a:t元素之后显示为a:t元素。

我正在开发一个解决方案,根据root用户是p:sld还是p:notes来应用两个不同的模板。当上下文是根元素时,将模板应用于"p:sld|p:notes"

如果它调整p:sld,xslt会查找将包含在<SlideTitleGhost>中的后代a:t的值,将该值存储在变量中,然后输出<SlideTitleGhost> $变量</SlideTitleGhost>,然后如上所述为后代a:t元素应用模板,除了将<SlideTitleGhost>中包含其内容的a:t元素删除。

如果选择p:notes,则只需应用a:t的模板。标记<PageBreak></PageBreak>开头的p:notes已在插入最后一个a:t元素时插入。

目前虽然我得到空输出。因此,欢迎任何有关我如何描述上述内容的建议。