Replacing more than one attributes in XSLT (with i

2019-08-14 09:38发布

问题:

Hi I have to replace more than one attributes of a given tag using XSLT while copying the entire file with identity template. With my given XSLT I'm able to replace one attribute (value of class) but not the other one. Input file:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta name="generator" content=
  "HTML Tidy for Linux/x86 (vers 11 February 2007), see www.w3.org" />
  <meta http-equiv="Content-type" content="text/html; charset=us-ascii" />

  <title></title>
</head>

<body>
  <!--OTHER STUFF-->    
  <div class="LR" id="12">
  </div>
  <!--OTHER STUFF-->
</body>
</html>

Output file:

<?xml version="1.0" encoding="utf-8"?>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta name="generator" content=
  "HTML Tidy for Linux/x86 (vers 11 February 2007), see www.w3.org" />
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title></title>
</head>

<body>
  <!--OTHER STUFF-->
  <div class="WZ" id="56">
  </div>
  <!--OTHER STUFF-->
</body>
</html>

My XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xhtml="http://www.w3.org/1999/xhtml"
 xmlns="http://www.w3.org/1999/xhtml"
 exclude-result-prefixes="xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*" />

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

<xsl:template match="xhtml:div[@id='12']/@class">
  <xsl:attribute name="class">WZ</xsl:attribute>
   <xsl:attribute name="id">56</xsl:attribute> 
</xsl:template>

</xsl:stylesheet>

Thanking you!

回答1:

Try matching @*:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="xhtml:div[@id='12']/@*">
    <xsl:attribute name="class">WZ</xsl:attribute>
    <xsl:attribute name="id">56</xsl:attribute>
</xsl:template>
</xsl:stylesheet>

This gives the desired result:

<div class="WZ" id="56"></div>


回答2:

This template also copies across any extra attributes the <div> node might have, and thus it is a more robust solution.

This template...

<xsl:template match="xhtml:div[@id='12']"
  xmlns="http://www.w3.org/1999/xhtml">
  <div id="56" class="WZ">
    <xsl:apply-templates select="
      (@*[local-name()!='id']
         [local-name()!='class'])
      | node()"/>
  </div>
</xsl:template>

...will tranform this element...

<div class="LR" id="12" other="x">

...into...

<div id="56" class="WZ" other="x" />

Notice that the extra attribute "other" is retained!


Update

More for general interest than answering the question, here is a couple of equivalent alternatives...

XSLT 1.0 Alternative

Here is another XSLT 1.0 template that does the same thing. It is less efficient but more concise (well, sort of)...

<xsl:template match="xhtml:div[@id='12']"
  xmlns="http://www.w3.org/1999/xhtml">
  <div>
    <xsl:apply-templates select="@*" />
    <xsl:attribute name="id">56</xsl:attribute>
    <xsl:attribute name="class">WZ</xsl:attribute>
    <xsl:apply-templates select="node()" />
  </div>
</xsl:template>

XSLT 2.0 Alternative

I know the OP is using XSLT 1.0. This is just for interest. Want both brevity and efficiency? Never fear! Help is here with this XSLT 2.0 alternative...

<xsl:template match="xhtml:div[@id='12']"
  xmlns="http://www.w3.org/1999/xhtml">
  <div id="56" class="WZ">
    <xsl:apply-templates select="@* except (@id,@class) | node()" />
  </div>
</xsl:template>