开发者

Removing Attributes from XSLT and working with result set

开发者 https://www.devze.com 2023-03-16 20:12 出处:网络
Is it possible to remove xml attributes from XSLT AND work with the resulting transform? In other words, I have the following XML:

Is it possible to remove xml attributes from XSLT AND work with the resulting transform?

In other words, I have the following 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>

I know that I can use the following XSLT to strip the attributes:

 <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()}" >
               开发者_Python百科 <xsl:apply-templates select ="@* | node()" />
            </xsl:element>
  </xsl:template>

But if I wanted to read the values, using the following template

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

Could I chain that template to the output of the first two?

Thanks in advance,

-R.


Is it possible to remove xml attributes from XSLT AND work with the resulting transform?

Yes, just search for "multi-pass transformation" and you'll find many answers with good code examples.

However, for what you want to do such transformation chaining is overly complex and completely unnecessary.

Just use:

<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>

And in case the default namespace of the XML document isn't known in advance, you can still produce the wanted results in a single pass:

<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>


There is something odd in this question: I don't see how the title of your question does match the contents.

In the title you are asking for a two-pass transform where the first pass must remove the attributes and the second must work on it.

In the contents you show two templates which outputs the local name of the nodes and attributes and, after, you show in another template that you'd like to work with the attributes getting their value... :)

As per @Dimitre's answer replied to the contents of your question (which does not address a real question I think) I will try to answer the title of your question, which seems much more interesting (and answerable).


Removing Attributes from XSLT ...

To remove the attributes (and obtain a transform without namespaces) you can work with an Identity Transformation. Because you want multi-pass you must copy the content of the transformation on a variable in the first pass.

You can use modes to address the process to the elements in the first pass.

... and working with result set

To work with result set (formally known as a result tree fragment) you need to apply the templates using a reference to the variable defined in the first pass. Welcome! This is the second pass :)

Two pass transformation is relatively much accessible in XSLT 2.0 than in XSLT 1.0, because of the XSLT 2.0 ability to apply templates to an RTF. In XSLT 1.0 you will need a specific extension function called node-set().


The XSLT 2.0 will look like this (pure example):

<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> 

with results (applied on your input example)

00

The XSLT 1.0 will look very similar, but the transform root element:

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

and the second pass:

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


Many transformations are best split into a pipeline where each stage of the pipeline performs one simple task.

You can do a multi-stage transformation within a single stylesheet (by holding the results in variables, especially with XSLT 2.0), or you can do it using multiple stylesheets. You can control a pipeline involving multiple stylesheets with a variety of technologies (XProc, Coccoon, Orbeon, Ant, xmlsh) or from your own Java/C# code. Using multiple stylesheets has the advantage that the components of the pipeline are highly reusable.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号