views:

40

answers:

2

I am trying to remove the "Hide this data" from this XML which is proceeded with the qualifier type="noView"

<element version="Local">
   <qualifier name="Public" type="View" /> 
    Good to go 
</element>
<element version="Local">
<qualifier name="Public" type="noView" /> 
     Hide this data
</element>

I am using this XSL

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
   <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="@*"/>
       <xsl:apply-templates/>
     </xsl:copy>
   </xsl:template>

<xsl:template match="qualifier">
   <xsl:call-template name="replace-noview" />
 </xsl:template>

<xsl:template name="replace-noview">
  <xsl:param name="text" select="@type"/>

  <xsl:choose>
  <xsl:when test="contains($text, 'noView')">
    <xsl:copy-of select="."/>
    <xsl:text>DELETED</xsl:text>
  </xsl:when>
  <xsl:otherwise>
    <xsl:copy-of select="."/>
  </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

The output I'm getting is

<element identifier="ContactName" version="Local">
<qualifier name="Public" type="View" />
Good to go 
</element>
<element identifier="ContactName" version="Local">
<qualifier name="Public" type="noView" />DELETED 
Hide this data 
</element>

I am matching the "noView" attribute and can add the "DELETED" text. However I need to remove the follow "Hide this data" text.

The output I would like is

<element identifier="ContactName" version="Local">
<qualifier name="Public" type="View" />
Good to go 
</element>
<element identifier="ContactName" version="Local">
<qualifier name="Public" type="noView" />
DELETED 
</element>
+1  A: 

Assuming that the element could contain more than one text ... try the following stylesheet:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="xml"/>

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

  <xsl:template match="text()">
    <xsl:choose>
      <xsl:when test="preceding-sibling::*[1][local-name() = 'qualifier' and @type='noView']">
    DELETED
  </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

The spacing is relevant for the output in the choose element. So that it looks alright in the output.

If the element only contains one text prefixed by an qualifier the stylesheed could be made easier.

Obalix
+1, This code is correct.
Dimitre Novatchev
+2  A: 

This transformation correctly produces the desired result:

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

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

 <xsl:template match="text()
  [preceding-sibling::*[1]/@type='noView']">
  <xsl:text>DELETED</xsl:text>
 </xsl:template>
</xsl:stylesheet>

When applied on the provided XML document (corrected to be well-formed):

<t>
 <element version="Local">
   <qualifier name="Public" type="View" />
    Good to go
 </element>
 <element version="Local">
 <qualifier name="Public" type="noView" />
     Hide this data
 </element>
</t>

The desired result is produced:

<t>
 <element version="Local">
   <qualifier name="Public" type="View">
</qualifier>
    Good to go
 </element>
 <element version="Local">
 <qualifier name="Public" type="noView">
</qualifier>DELETED</element>
</t>

Note the use of the Identity rule and its overriding just for the text nodes that need special processing. Using and overriding the identity rule is one of the most fundamental XSLT design patterns.

Dimitre Novatchev
+1, it is just more elgant ... :-)
Obalix