2011-02-28 57 views
2

做这个搜索,并没有找到答案的兄弟姐妹,所以这里去...XSLT:让孩子节点上下文节点

我有类似下面的一些XML:

<?xml version="1.0" encoding="utf-8"?> 
<footnote ref="1"> 
    <para>Here is some text about some guy who made 
     <emphasis role="italic">fascinating</emphasis> comment I want to quote 
     <blockquote> So I went to this place and met this guy....</blockquote> 
     It seemed more interesting at the time. 
    </para> 
</footnote> 

我想用XSLT将其更改为一个新的模式(使用新的命名空间前缀)

<?xml version="1.0" encoding="utf-8"?> 
<nns:footnote ref="1"> 
    <nns:fn-para>Here is some text about some guy who made 
     <nns:emph type="it">fascinating</nns:emph> comment I want to quote: 
    </nns:fn-para> 
    <nns:fn-blockquote> 
     <nns:bq-para>So I went to this place and met this guy....</nns:bq-para> 
    </nns:fn-blockquote> 
    <nns:fn-para> It seemed more interesting at the time.</nns:fn-para> 
</nns:footnote> 

我已经试过一些东西......采取对那脚注的后裔,并通过循环孩子们,但这是问题因为它不仅是para中的文本节点,还有emph标签,所以我仍然不知道如何将子节点放置在树上并放置在结果树中......这是否合理?

回答

3

编辑:小重构和扩展解释。

这个样式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:nns="nns"> 
    <xsl:key name="kNodeByPrecedingBlock" 
      match="para/node()[not(self::blockquote)]" 
      use="generate-id(
        (..|preceding-sibling::*[self::blockquote][1])[last()] 
       )"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="footnote"> 
     <nns:footnote> 
      <xsl:apply-templates select="node()|@*"/> 
     </nns:footnote> 
    </xsl:template> 
    <xsl:template match="para"> 
     <xsl:apply-templates select=".|blockquote" mode="group"/> 
    </xsl:template> 
    <xsl:template match="emphasis"> 
     <nns:emph> 
      <xsl:apply-templates select="node()|@*"/> 
     </nns:emph> 
    </xsl:template> 
    <xsl:template match="emphasis/@role"> 
     <xsl:attribute name="type"> 
      <xsl:value-of select="substring(.,1,2)"/> 
     </xsl:attribute> 
    </xsl:template> 
    <xsl:template match="blockquote"> 
     <nns:fn-blockquote> 
      <nns:bq-para> 
       <xsl:apply-templates/> 
      </nns:bq-para> 
     </nns:fn-blockquote> 
    </xsl:template> 
    <xsl:template match="para" mode="group" name="makePara"> 
     <xsl:variable name="vGroup" 
      select="key('kNodeByPrecedingBlock',generate-id())"/> 
     <xsl:if test="$vGroup"> 
      <nns:fn-para> 
       <xsl:apply-templates select="$vGroup"/> 
      </nns:fn-para> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="*" mode="group"> 
     <xsl:apply-templates select="."/> 
     <xsl:call-template name="makePara"/> 
    </xsl:template> 
</xsl:stylesheet> 

输出:

<nns:footnote ref="1" xmlns:nns="nns"> 
    <nns:fn-para>Here is some text about some guy who made 
     <nns:emph type="it">fascinating</nns:emph> comment I want to quote 
    </nns:fn-para> 
    <nns:fn-blockquote> 
     <nns:bq-para> So I went to this place and met this guy....</nns:bq-para> 
    </nns:fn-blockquote> 
    <nns:fn-para>   It seemed more interesting at the time. 
    </nns:fn-para> 
</nns:footnote> 

注意:用于覆盖身份规则(只是风格,但它是一个很好的模式)。匹配footnote,emphasis,@role属性emphasis和的四个直接转换规则。分组键匹配“内嵌”para的孩子:第一个前面的“块”元素或para父项的生成ID。分组规则para将模板应用于"group"模式中的自我和“块”元素。规则匹配para"group"模式(也叫makePara):输出一个段落,如果有一个组上下文节点生成id作为键值。规则匹配"group"模式中的任何元素(它将是任何“块”元素):将模板应用于自我(“重置”模式)并呼叫makePara命名模板。

+0

+1为一个很好的答案。 – 2011-03-01 04:13:01

+0

+1好的分组风格。 – Flack 2011-03-01 05:13:47

+0

非常感谢这个答案,这是工作得很好,虽然我很尴尬地说在这一刻,我没有100%直观的理解为什么它的作品...将阅读更多的关键和尝试用这种基本方法做一些不同的事情。再次感谢! – badperson 2011-03-01 16:43:30