【问题标题】:Conditional XSLT transformation in PHPPHP 中的条件 XSLT 转换
【发布时间】:2009-08-25 18:23:02
【问题描述】:

我有一条XML 数据需要转换成WML

是这样的:

 <root>
  <category name="music"/>
  <subcategory name="classic"/>
  <subcategory name="rock"/>
  <subcategory name="Techno"/>
  <node type="music" subtype="classic" name="beethoven"/>
  <node type="music" subtype="classic" name="chopin"/>
  <record author="beethoven" name="moonlight sonata"/>
  …
 </root>

我无法更改文件结构。

一些Nokia 移动浏览器无法将大量&lt;card&gt; 加载到内存中。

因此,根据移动浏览器的不同,WML 页面应该是一整套 &lt;card&gt;&lt;card&gt; 的某个子集。

例如,如果我用普通浏览器下载一个页面,它应该是这样的:

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="#music">music</a></p>
  <p><a href="#video">video</a></p>
  <p><a href="#java">java</a></p>
 </card>
 <card id="az">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 <card id="music">
  <p><a href="#classic">classic</a></p>
  <p><a href="#rock">rock</a></p>
  <p><a href="#Techno">Techno</a></p>
 </card>
 <card id="classic">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 …
</wml>

,以便用户无需额外往返服务器即可浏览。

但是,当我使用Nokia 并访问起始页时,页面应如下所示:

http://example.com/

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="#music">music</a></p>
  <p><a href="#video">video</a></p>
  <p><a href="#java">java</a></p>
 </card>
 <card id="az">
  <p><a href="/beethoven">beethoven</a></p>
  <p><a href="/chopin">chopin</a></p>
 </card>
 <card id="music">
  <p><a href="/classic">classic</a></p>
  <p><a href="/rock">rock</a></p>
  <p><a href="/Techno">Techno</a></p>
 </card>
 <card id="video">
  <p><a href="/movies">Movies</a></p>
 </card>
 <card id="java">
  <p><a href="/games">Games</a></p>
 </card>
</wml>

,当我访问href时,它应该显示内部内容:

http://example.com/classic

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="/music">music</a></p>
  <p><a href="/video">video</a></p>
  <p><a href="/java">java</a></p>
 </card>
 <card id="az">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 <card id="classic">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 …
</wml>

基本上,XSLT 应该做以下事情:

  • 接受要显示的某种参数:类别、子类别等。

  • 计算将显示的&lt;card&gt;

    1. 如果我们只加载类型和目录,我们会得到2 卡片(我们总是显示它们)
      • 如果我们只加载类型和子类型,我们会得到10 卡片。
      • 如果我们加载类型、子类型和标题,我们会显示 100 卡片。
      • 如果我们加载所有内容,我们会显示 300 卡片。

    Nokia 不能处理超过120 的卡片,所以我们只停留在3 级别。

    如果XML 发生变化并且3 级别需要130 卡片,我们应该在2 级别停止。

  • 如果&lt;card&gt; 低于某个级别,则不要显示它

  • 如果不显示卡片,请将#(内部链接)替换为/(外部链接)。

是否可以在单个XSL 文件中执行?

【问题讨论】:

  • 只有一级 URL 吗?斜线+关键字,就这样?这不会导致歧义吗?还是网址是结构化的?
  • 不,不会。它旨在一次容纳所有卡片,并且它们需要具有不同的名称。刚刚测试的时候出现的问题。
  • 所以我可以相信@names 在所有类别/子类别/节点/记录元素中都是唯一的?
  • @Tomalak:绝对。其实id就是typeGUIDsubGUIDnameGUID等等,为了简洁,我用了实名。
  • 好的。您所说的这些限制是完全要在 XSL 中处理还是在基础数据中处理?例如:是否有不超过 8 个子类型(8+2=10 张卡片,包括 toc 和 a-z)?

标签: xml xslt wml


【解决方案1】:

我不确定问题到底是什么。正如所言,答案是“是的,有可能” - xsl:ifxsl:choose 应该足以处理您的所有情况。您必须通过参数向样式表传达限制(例如结果将发送到诺基亚的事实) - 请参阅xsl:param

【讨论】:

    【解决方案2】:

    我建议创建变量来累计计算每个“级别”(类型、子类型、标题等)的所有节点,并为您的 XSL 提供一个参数,指示要生成的最大卡片数。 XSL 可能看起来像这样:

    <xsl:stylesheet …>
      <xsl:param name="max-cards" select="999999"/>
    
      <xsl:template match="/root">
        <!-- "2" here for the type/TOC cards -->
        <xsl:variable name="nSubs" select="2 + count(subcategory)"/>
        <xsl:variable name="nNodes" select="$nSubs + count(node)"/>
        <xsl:variable name="nRecs" select="$nNodes + count(record)"/>
    
        <!-- generate types & TOC here -->
    
        <xsl:if test="$nSubs < $max-cards">
            <!-- generate subtypes here -->
        </xsl:if>
    
        <xsl:if test="$nNodes < $max-cards">
            <!-- generate titles here -->
        </xsl:if>
    
        <xsl:if test="$nRecs < $max-cards">
            <!-- generate everything else here -->
        </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    样式表参数可以类似地用于限制上层的生成,但是对于 SO 来说,这样的例子太长了。 ^.^

    【讨论】:

      【解决方案3】:

      我的理解是 XSL 正在完善,因此几乎可以回答任何“有可能吗?”问题将是肯定的。 “你会喜欢它吗?”的答案,也许不是那么多:-)

      实现它并保持模块化的一种简单方法是使用

      如果您的格式有共同点,您可以通过将这些部分委托给它们自己的模板或函数来干掉它,在主要格式的更高级别模板中重用它们。基本上是分而治之。

      编辑:更具体地说,我所说的委托是什么意思,我的意思是显式调用模板并将它们参数化,例如:

         <xsl:call-template name="showcard">
           <xsl:with-param name="kind" select="nokia"/>
         </xsl:call-template>
      

      通过将这些模板依次委托给其他模板等。您还可以从 value-of 和 apply-templates 中获得很多好处,这些模板将流程引导到特定模板。尽管您的案例可能更简单,但这可能会导致代码更具可读性。

      【讨论】:

      • 事实上,我想要的是有一个可重复使用的模板,所以如果我想更改卡片布局,我会在一个地方完成(Nokia 和普通浏览器)。我知道参数和选择,但我无法正确使用它们,我得到的一切看起来都是一团糟。
      • 是的,但这仍然只是一个 xsl 文件,带有一堆 xsl:template 组件来下降 xml 输入。我认为 xsl:template 是一个子例程或过程/函数。
      猜你喜欢
      • 1970-01-01
      • 2017-07-20
      • 1970-01-01
      • 2015-10-14
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多