2009-06-24 29 views
2

比方说,我有一个空的XML文件,像这样:可能对动态生成的xml执行xsl转换吗?

<root></root> 

而且我想一个XSL转换,像这样在添加到根元素:

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

    <xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" /> 

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

    <xsl:template match="/"> 
    <xsl:copy> 
     <xsl:element name="root"> 
     <xsl:element name="label">Some text</xsl:element> 
     </xsl:element> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

转换XML文件给我:

<root> 
    <label>Some text</label> 
</root> 

但是,我想修改XSL文件,以便我可以转换运行时生成的XML。基本上,我希望XSL认为原始XML文件包含动态创建的XML,然后对其进行HTML转换。

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

    <xsl:output method="html" encoding="UTF-8" omit-xml-declaration="yes" /> 

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

    <xsl:template match="/"> 
    <xsl:copy> 
     <xsl:element name="root"> 
     <xsl:element name="label">Some text</xsl:element> 
     </xsl:element> 
    </xsl:copy> 
    </xsl:template> 

    <!-- This part is new --> 
    <xsl:template match="//label"> 
    <b> 
     <xsl:value-of select="." /> 
    </b> 
    </xsl:template> 

</xsl:stylesheet> 

在这种情况下,我的期望输出将是:<b>label</b>

是否可以在一个XSL文件中做到这一点?我是否错误地查看了这个问题?

回答

0

道格的答案是技术上是正确的,他把我找的节点集扩展功能在正确的道路上(谢谢!)。唯一的区别是我使用Xalan-java处理器而不是微软处理器。这里是工作的我试图才达到(非常简单的)例子:调用模板(“someTemplate”)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xalan="http://xml.apache.org/xalan" exclude-result-prefixes="xalan"> 
<xsl:output method="html" encoding="UTF-8" omit-xml-declaration="yes"/> 

<xsl:template match="label"> 
    <b><xsl:value-of select="." /></b> 
</xsl:template> 

<xsl:template name="someTemplate"> 
    <root> 
     <label>hey there</label> 
    </root> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:variable name="gen"> 
     <xsl:call-template name="someTemplate" /> 
    </xsl:variable> 

    <xsl:apply-templates select="xalan:nodeset($gen)//label" /> 
</xsl:template> 

</xsl:stylesheet> 

的基本想法是,你创建一个变量(这里命名为“根”),这创建一些XML。该xml树随后由xalan:nodeset函数进行处理。在这里,我运行apply-templates并处理所有与我的标签模板匹配的标签字段,并创建粗体标签。

我之所以这么做是因为我正在开发一个web应用程序,每个页面上的所有内容都是用XML定义的,然后使用XSL进行处理。这很好,直到你想用AJAX调用的结果填充页面的某些部分,因为那么你需要从返回的XML(杂乱和糟糕)中在JavaScript函数内部构建新的html,或者通过AJAX XML响应服务器端的XSL转换,只需将xhtml结果插入页面即可。

在我的情况下,因为我用XML描述每个网页,所以我创建了具有“类型”的简单通用元素。我的元素是“块”,它是任何内容块。块可以具有诸如“按钮”(其是链接或按钮),“列表”(其是多个块),“图像”或“输入”的子节点。模式的细节是不相关的;我只是想表明我的XML模式非常简单和通用。

另一方面,我检索的用于刷新/构建页面的AJAX XML响应由不使用我的模式的第三方创建。相反,它们提供的每个服务都会为每个唯一请求返回非常具体的XML。出于这个原因,我需要一种方法将其非常具体的XML转换为我的非常通用的XML,以便我可以使用一组XSL模板进行转换。

下面是我正在使用的xsl模板之一的示例,它转换AJAX响应并将其特定的XML转换为我的通用XML。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xalan="http://xml.apache.org/xalan" exclude-result-prefixes="xalan"> 
<xsl:output method="html" encoding="UTF-8" omit-xml-declaration="yes"/> 

<!-- base.xsl includes a generic template that matches all blocks and routes 
     to the needed template based on the block type --> 
<xsl:include href="base.xsl" /> 

<xsl:template name="templateForAJAXResponse"> 
    <block> 
     <type>list</type> 
     <list> 
      <type>itemBrowser</type> 
      <xsl:for-each select="/response/items/item"> 
       <block> 
        <type>button</type> 
        <button> 
         <type>imageButton</type> 
         <href>something.action</href> 
         <src><xsl:value-of select="src" /></src> 
         <title><xsl:value-of select="name" /></title> 
        </button> 
       </block> 
      </xsl:for-each> 
     </list> 
    </block> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:variable name="gen"> 
     <xsl:call-template name="templateForAJAXResponse" /> 
    </xsl:variable> 

    <div> 
     <xsl:apply-templates select="xalan:nodeset($gen)/block" /> 
    </div> 
</xsl:template> 

</xsl:stylesheet> 
3

运行多通变换有三个基本元素。

  • <xsl:import>
  • <xsl:apply-imports>
  • node-set()扩展函数

示例穿过两个变换串联的XML文档。也就是说,它通过一个转换来传递内容,删除名称空间节点,然后从第一个转换中获取输出,并将其传递给第二个转换,以更改文档的标题。在这种情况下,文档是一个XHTML文档。第二次转换的写法是,它不能接受定义了名称空间的XHTML文档。

原始XHTML文档

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
    <title>This is the old title</title> 
    </head> 
    <body> 
    <p>This is some text.</p> 
    </body> 
</html> 

通1后(除去命名空间节点)

<html> 
    <head> 
    <title>This is the old title</title> 
    </head> 
    <body> 
    <p>This is some text.</p> 
    </body> 
</html> 

结果(后通2)

注意,标题文本已经改变。

<html> 
    <head> 
    <title>This is the new title</title> 
    </head> 
    <body> 
    <p>This is some text.</p> 
    </body> 
</html> 

XSLT进行通1

这个转换在这个文件中内容应用模板删除命名空间节点,但副本内容的其余部分。然后,在传递2期间,通过使用<xsl:apply-imports>标签应用在导入的XSLT中定义的模板。通过2的模板是使用<xsl:import>标签导入的。

第一遍的结果存储在名为“treefrag”的变量中。使用扩展功能“node-set()”将树片段转换为节点集。在本例中,使用Microsoft XML分析器4.0,因此声明了urn:schemas-microsoft-com:xslt命名空间。

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
> 

    <xsl:import href="pass2.xslt" /> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> 

    <xsl:template match="/"> 
    <xsl:param name="pass">1</xsl:param> 

    <xsl:choose> 
     <xsl:when test="$pass=1"> 
     <xsl:variable name="treefrag"> 
      <xsl:apply-templates> 
      <xsl:with-param name="pass" select="$pass" /> 
      </xsl:apply-templates> 
     </xsl:variable> 
     <xsl:variable name="doc" select=" 
      msxsl:node-set($treefrag) 
     " /> 
     <xsl:apply-templates select="$doc"> 
      <xsl:with-param name="pass">2</xsl:with-param> 
     </xsl:apply-templates> 
     </xsl:when> 
     <xsl:when test="$pass=2"> 
     <xsl:apply-imports /> 
     </xsl:when> 
    </xsl:choose> 

    </xsl:template> 

    <!-- identity template without namespace nodes --> 
    <xsl:template match="*"> 
    <xsl:param name="pass">2</xsl:param> 

    <xsl:choose> 
     <xsl:when test="$pass=1"> 
     <xsl:element name="{name()}"> 
      <xsl:apply-templates select="@*|node()"> 
      <xsl:with-param name="pass" select="$pass" /> 
      </xsl:apply-templates> 
     </xsl:element> 
     </xsl:when> 
     <xsl:when test="$pass=2"> 
     <xsl:apply-imports /> 
     </xsl:when> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="@*|text()|comment()|processing-instruction()"> 
    <xsl:param name="pass">2</xsl:param> 

    <xsl:choose> 
     <xsl:when test="$pass=1"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"> 
      <xsl:with-param name="pass" select="$pass" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
     </xsl:when> 
     <xsl:when test="$pass=2"> 
     <xsl:apply-imports /> 
     </xsl:when> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

XSLT用于通2

这只是变换更改标题标签的内容可以复制内容的所有的休息。

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

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

    <xsl:template match="title"> 
    <title>This is the new title</title> 
    </xsl:template> 

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

</xsl:stylesheet> 

来源的文章:"XSLT: Multi-pass transforms"

+0

感谢您的回答,Doug。这使我走上了正确的轨道,我能够想出一个解决我的真实问题的方法,详细地列出了我自己发布的答案。 – 2009-06-25 15:12:20