从XSLT中删除属性并使用结果集

时间:2011-06-30 00:27:11

标签: xml xslt transform chaining

是否可以从XSLT中删除xml属性并使用生成的转换?

换句话说,我有以下XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="XML_TEST.xslt"?>
<report xmlns="abc123">
<book>
<page id="22">

</page>
<page id="23">

</page>
</book>
</report>

我知道我可以使用以下XSLT去除属性:

 <xsl:template match ="@*" >
            <xsl:attribute name ="{local-name()}" >
                <xsl:value-of select ="." />
            </xsl:attribute>
            <xsl:apply-templates/>
        </xsl:template>
        <xsl:template match ="*" >
            <xsl:element name ="{local-name()}" >
                <xsl:apply-templates select ="@* | node()" />
            </xsl:element>
  </xsl:template>

但如果我想阅读这些值,请使用以下模板

<xsl:template match="report">
    <xsl:for-each select="book/page">
        <xsl:value-of select="@id"/>
    </xsl:for-each>
</xsl:template>

我可以将该模板链接到前两个的输出吗?

提前致谢,

-R

3 个答案:

答案 0 :(得分:1)

  

是否可以删除xml   来自XSLT的属性和使用   结果变换?

是的,只需搜索“多次转化”,您就可以找到很多具有良好代码示例的答案。

但是,对于您想要做的事情,此类转换链接过于复杂且完全没必要

只需使用:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="abc123" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="x:page">
  <xsl:value-of select="@id"/>
 </xsl:template>
</xsl:stylesheet>

如果事先不知道XML文档的默认命名空间,您仍然可以一次性生成想要的结果

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

 <xsl:template match="*[name()='page']">
  <xsl:value-of select="@id"/>
 </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

这个问题有些奇怪:我看不出你的问题标题与内容的匹配程度

在标题中,您要求进行两次传递转换,其中第一次传递必须删除属性,第二次传递必须对其进行处理。

在内容中,您会显示两个输出节点和属性的本地名称的模板,之后,您会在另一个模板中显示您希望使用属性获取其值。 .. :))

根据@Dimitre的回答回复了你问题的内容(我认为这并没有解决真正的问题)我会尝试回答你问题的标题 ,这看起来更有趣(并且可以回答)。


  

从XSLT中移除属性 ...

要删除属性(并获取没有名称空间的转换),您可以使用Identity Transformation。因为您需要多次传递,所以必须在第一次传递中复制变量的内容。

您可以使用modes来解决第一遍中元素的过程。

  

...并使用结果集

要使用结果集(正式名称为result tree fragment),您需要使用引用第一遍中定义的变量来应用模板。欢迎!这是第二遍:)

由于XSLT 2.0能够将模板应用于RTF,因此XSLT 2.0中的两次传递转换比XSLT 1.0更易于访问。在XSLT 1.0中,您将需要一个名为node-set()的特定扩展函数。


XSLT 2.0看起来像这样(纯粹的例子):

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

    <xsl:output indent="yes" omit-xml-declaration="yes"/>   
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/">
        <xsl:variable name="FirstPass">
            <xsl:copy>
                <xsl:apply-templates select="/" mode="FirstPass"/>
            </xsl:copy>
        </xsl:variable>

        <xsl:apply-templates select="$FirstPass/report/book/page"/>
    </xsl:template>

    <xsl:template match="node()" mode="FirstPass">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select ="node()" mode="FirstPass"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="page">
        <xsl:value-of select="count(@*)"/>
    </xsl:template>

</xsl:stylesheet> 

结果(应用于您的输入示例)

00

XSLT 1.0 看起来非常相似,但转换根元素:

<xsl:stylesheet   
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
xmlns:x="abc123"
xmlns:exslt="http://exslt.org/common"
version="2.0">

第二次传递

 <xsl:apply-templates select="exslt:node-set($FirstPass)/report/book/page"/>

答案 2 :(得分:0)

许多转换最好分成一个管道,管道的每个阶段都执行一个简单的任务。

您可以在单个样式表中进行多阶段转换(通过将结果保存在变量中,尤其是使用XSLT 2.0),或者您可以使用多个样式表来执行此操作。您可以使用各种技术(XProc,Coccoon,Orbeon,Ant,xmlsh)或您自己的Java / C#代码控制涉及多个样式表的管道。使用多个样式表的优点是管道的组件具有高度可重用性。