开发者

How to copy a node set into a resultant attribute using XSLT without white space and tags encoded?

Given this XML...

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <item>
        <this>
<that>one</that>
        </this>
    </item>
    <item>
        <this>
<that>two</that>
        </this>
    </item>
    <item>
        <this>
<that>three</that>
        </this>
    </item>
</root>

I want to make copies of the items into a new format which looks like...

<new>
  <parm x="&gt;that&lt;one&gt;/that&lt;"/>
  <parm x="&gt;that&lt;two&gt;/that&lt;"/>
  <parm x="&gt;that&lt;three&gt;/that&lt;"/>
</new>

The style sheet...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:param name="feedKey"/>

    <xsl:template match="/">
        <new>
            <xsl:apply-templates select="//item"/>
        </new>
    </xsl:template>

    <xsl:template match="item">
        <xsl:element name="param">
            <xsl:attribute name="x"><xsl:copy-of select="node()"/></xsl:attribute>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

...produces...

<?xml version="1.0" encoding="UTF-8"?>
<new>
   <param x="&#xA;        &#xA;one&#xA;        &#xA;    "/>
   <param x="&#xA;        &#xA;two&#xA;        &#xA;    "/>
   <param x="&#xA;        &#xA;three&#xA;        &#xA;    "/>
</new>

A simple change to the sheet to remove the attribute...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:param name="feedKey"/>

    <xsl:template match="/">
        <new>
            <xsl:apply-templates select="//item"/>
        </new>
    </xsl:template>

    <xsl:template match="item">
        <xsl:element name="param">
            <xsl:copy-of select="node()"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

...produces...

<?xml version="1.0" encoding="UTF-8"?>
<new>
   <param>
        <this>
         <that>one</that>
        </this>
    </param>
   <param>
        <this>
         <that>two</that>
        开发者_如何学Python</this>
    </param>
   <param>
        <this>
         <that>three</that>
        </this>
    </param>
</new>

How can I convert "this" into attribute "x" with the white space stripped and the tags encoded?


This transformation:

<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="/">
  <new>
    <xsl:apply-templates select="*/*/this/*"/>
  </new>
 </xsl:template>

 <xsl:template match="*">
  <xsl:variable name="vStr">
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>&gt;</xsl:text>

    <xsl:apply-templates/>

    <xsl:text>&lt;/</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>&gt;</xsl:text>
  </xsl:variable>

  <parm x="{$vStr}"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <item>
        <this>
            <that>one</that>
        </this>
    </item>
    <item>
        <this>
            <that>two</that>
        </this>
    </item>
    <item>
        <this>
            <that>three</that>
        </this>
    </item>
</root>

produces the desired result:

<new>
    <parm x="&lt;that&gt;one&lt;/that&gt;"/>
    <parm x="&lt;that&gt;two&lt;/that&gt;"/>
    <parm x="&lt;that&gt;three&lt;/that&gt;"/>
</new>


To my knowledge and if I understand your question correctly; there isn't a way of doing this included in XSLT. My assumption is that W3C consider storing escaped XML to be an anti-pattern. My approach was to define a named template:

<xsl:template name='recursive_escape'>
<xsl:text>;&lt;</xsl:text>
<xsl:value-of select='local-name()'/>
<xsl:for-each select='child::attribute()'>
<xsl:value-of select='local-name()'/>
<xsl:text>='</xsl:text><xsl:value-of select='.'/><xsl:text>'</xsl:text>
</xsl:for-each>
<xsl:text>/;&gt;</xsl:text>....

And so on. I hope you can decipher what I'm trying to do here: construct manually an opening tag with the name of the context node and the name and value of each attribute, then iterate through every child node of the context node and call the same template again; and so on. I don't have my original implementation to hand here so no doubt there's a few things wrong with my example; it's just a guide.

If anybody knows of a better way I'd like to hear it; it may be in XSLT 2.0 which isn't formalised yet, IIRC. For robustness and MSXML support, it's going to have to be XSLT 1.0.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜