2

我有多个 xml 实例,类似于以下内容:

<refbody>
<ul>
    <li><uicontrol>FOO</uicontrol>BAR</li>
</ul>
<p>Values: 000 - 999</p>
<ul>
    <li><uicontrol>FOO</uicontrol>BAR</li>
    <li><uicontrol>FOO</uicontrol>BAR</li>
    <li><uicontrol>FOO</uicontrol>BAR</li>
    <li><uicontrol>FOO</uicontrol>BAR</li>
</ul>
<p>Values:</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
<p>lorem ipsum</p>
</refbody>

我希望发生的事情是将所有<ul>元素合并到一个<dl>.

每个都<li>应该创建一个 child <dlentry>

每个都<uicontrol>应该成为<dt>它的一个孩子<dlentry>

中的剩余文本<li>应该放在一个<dd>元素中,该元素也是<dlentry>.

我的样式表(在下面提供)已经完成了很多。我遇到麻烦的地方是最后一个要求:

任何<p>需要放在<dlentry>与其关联的内部preceding-sibling::li[1]

所以想要的结果是这样的:

<refbody>
<dl>
    <dlentry>
        <dt>FOO</dt>
        <dd>BAR
            <p>Values: 000 - 999</p>
        </dd>
    </dlentry>
    <dlentry>
        <dt>FOO</dt>
        <dd>BAR</dd>
    </dlentry>
    <dlentry>
        <dt>FOO</dt>
        <dd>BAR</dd>
    </dlentry>
    <dlentry>
        <dt>FOO</dt>
        <dd>BAR</dd>
    </dlentry>
    <dlentry>
        <dt>FOO</dt>
        <dd>BAR
            <p>Values:</p>
            <p>lorem ipsum</p>
            <p>lorem ipsum</p>
            <p>lorem ipsum</p>
        </dd>
    </dlentry>
</dl>
</refbody>

我想我需要使用密钥来执行此操作,但我无法让它正常工作。如果有人能告诉我我做错了什么,我将不胜感激。

这是我的样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:key name="kValues" match="p" 
    use="generate-id[preceding::li[1]]"/>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="ul[ancestor::refbody][1]">
    <dl>
        <xsl:for-each select="child::li|following::li">
            <xsl:variable name="vValues">
                <xsl:value-of select="key('kValues',generate-id())"/>
            </xsl:variable>
            <dlentry>
                <dt>
                    <xsl:value-of select="child::uicontrol"/>
                </dt>
                <dd>
                     <xsl:value-of select="text()"/>
                    <xsl:if test="$vValues">
                        <xsl:copy-of select="$vValues" />
                    </xsl:if>
                </dd>
            </dlentry>
        </xsl:for-each>
    </dl>
</xsl:template>

</xsl:stylesheet>
4

2 回答 2

1

以下样式表在不使用键的情况下生成所需的输出。

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="refbody">
        <xsl:copy>
            <dl>
                <xsl:apply-templates select="ul" />
            </dl>
        </xsl:copy>        
    </xsl:template>

    <xsl:template match="ul">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="li">
        <dlentry><xsl:apply-templates select="@*|node()"/></dlentry>
    </xsl:template>

    <xsl:template match="uicontrol">
        <dt><xsl:apply-templates select="@*|node()"/></dt>
    </xsl:template>

    <xsl:template match="li/text()">
        <dd>
            <xsl:copy/>
            <xsl:apply-templates 
                 select="parent::li
                                 [not(following-sibling::li)]
                                 /parent::ul
                                 /following-sibling::p
                                 [
                                  count(preceding-sibling::ul) 
                                  = count(current()/../../preceding-sibling::ul)
                                    +1
                                 ]"/>
        </dd>
    </xsl:template>

</xsl:stylesheet>
于 2012-07-26T00:39:03.293 回答
1

I. 这种转换(我使用密钥的解决方案):

<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="kFollowing"
      match="node()[self::p or self::text() and preceding-sibling::ul]"
      use="generate-id(preceding::li[1])"/>

     <xsl:template match="/*[ul]">
         <refbody>
             <dl>
               <xsl:apply-templates/>
             </dl>
         </refbody>
     </xsl:template>

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

     <xsl:template match="li/text()">
         <dd>
           <xsl:value-of select="normalize-space()"/>
         </dd>
     </xsl:template>

     <xsl:template match="li[last()]/text()">
         <dd>
           <xsl:value-of select="."/>
           <xsl:copy-of select="key('kFollowing', generate-id(..))"/>
         </dd>
     </xsl:template>

     <xsl:template match="uicontrol">
         <dt>
           <xsl:apply-templates/>
         </dt>
     </xsl:template>
     <xsl:template match="p/text()"/>
</xsl:stylesheet>

应用于提供的 XML 文档时

<refbody>
    <ul>
        <li>
            <uicontrol>FOO</uicontrol>BAR
        </li>
    </ul>
    <p>Values: 000 - 999</p>
    <ul>
        <li>
            <uicontrol>FOO</uicontrol>BAR
        </li>
        <li>
            <uicontrol>FOO</uicontrol>BAR
        </li>
        <li>
            <uicontrol>FOO</uicontrol>BAR
        </li>
        <li>
            <uicontrol>FOO</uicontrol>BAR
        </li>
    </ul>
    <p>Values:</p>
    <p>lorem ipsum</p>
    <p>lorem ipsum</p>
    <p>lorem ipsum</p>
</refbody>

产生想要的正确结果

<refbody>
   <dl>
      <dlentry>
         <dt>FOO</dt>
         <dd>BAR
        <p>Values: 000 - 999</p>
         </dd>
      </dlentry>
      <dlentry>
         <dt>FOO</dt>
         <dd>BAR</dd>
      </dlentry>
      <dlentry>
         <dt>FOO</dt>
         <dd>BAR</dd>
      </dlentry>
      <dlentry>
         <dt>FOO</dt>
         <dd>BAR</dd>
      </dlentry>
      <dlentry>
         <dt>FOO</dt>
         <dd>BAR
        <p>Values:</p>
            <p>lorem ipsum</p>
            <p>lorem ipsum</p>
            <p>lorem ipsum</p>
         </dd>
      </dlentry>
   </dl>
</refbody>

二、纠正所有发现的错误后的解决方案:

<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 
    <xsl:key name="kValues" match="p"
        use="generate-id(preceding::li[1])"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ul[ancestor::refbody][1]">
        <dl>
            <xsl:for-each select="child::li|following::li">
                <xsl:variable name="vValues" select="key('kValues',generate-id())"/>
                <dlentry>
                    <dt>
                        <xsl:value-of select="child::uicontrol"/>
                    </dt>
                    <dd>
                         <xsl:value-of select="text()[normalize-space()]"/>
                         <xsl:copy-of select="$vValues" />
                    </dd>
                </dlentry>
            </xsl:for-each>
        </dl>
    </xsl:template>
    
    <xsl:template match="p|ul|text()"/>
</xsl:stylesheet>

当这个更正的转换应用于同一个 XML 文档(上图)时,它会产生完全想要的正确结果


三、分析我发现的错误

  1. 这是一个需要用眼睛看的错误:

...

<xsl:key name="kValues" match="p"             
         use="generate-id[preceding::li[1]]"/> 

...

这里任何元素都由其具有前面p的子元素的字符串值索引。generate-idli

generate-id但是, XML 文档中没有命名元素。

真正的意图是使用该generate-id()功能。函数调用由函数名组成,后跟一系列实际参数值,用常规的圆括号(和. 括起来)。用方括号替换圆括号从根本上改变了表达式的语义,将函数调用变成了(相对)定位步骤。

.2.

        <xsl:variable name="vValues">                               
          <xsl:value-of select="key('kValues',generate-id())"/>                           
        </xsl:variable>

不仅是一种(非常)不好的做法,而且经常是错误的原因,就像在当前情况下一样。您正在创建树(文档节点),而不是元素的节点集。树总是至少有一个节点(文档节点)和它的布尔值,因此总是正确的。

永远不要使用上述语法。

正确的变量声明是

            <xsl:variable name="vValues" select="key('kValues',generate-id())"/>

.3. 没有模板规则可以防止身份模板复制任何不需要的ulptext()节点,并且这些出现在原始转换的结果中。

于 2012-07-26T02:40:08.240 回答