2

I want to learn how to search for a word in xml file and delete the entire line using xslt

Example: abc.xml

<server>
  <mbean code="org.jboss.varia.property.SystemPropertiesService" 
     name="abc.props:type=Service,name=abcprop">
  <attribute name="Properties">
         abc.def.ghi=123
         ghi.klm.nop=123
         qrst.tuv.wxy=123
         zab.cde.fgh=123
         ijk.lmn.opq=remove
         rst.uvw.xyz=123
         abc.tuv.nop=123
         ajc.dzf.goi=123
   </attribute>
 </mbean>
</server>

From the above example I want to search for a word "remove" and delete the complete line: ijk.lmn.opq=remove

Expected output is:

<server>
      <mbean code="org.jboss.varia.property.SystemPropertiesService" 
         name="abc.props:type=Service,name=abcprop">
      <attribute name="Properties">
             abc.def.ghi=123
             ghi.klm.nop=123
             qrst.tuv.wxy=123
             zab.cde.fgh=123
             rst.uvw.xyz=123
             abc.tuv.nop=123
             ajc.dzf.goi=123
       </attribute>
     </mbean>
    </server>

Update:

I tried the following code

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[(@* != 'DELETE')]"/>
</xsl:stylesheet>

Some how its not working, its deleting every thing in an xml file and showing an empty file.

kumar
  • 389
  • 1
  • 9
  • 28
  • In the XML file, are the lines separated by linefeeds, or is every line in an element of its own? – Mr Lister Aug 06 '13 at 13:45
  • I am not sure what linefeeds is but every line is on its own, If i delete a line, there wont be any empty line. – kumar Aug 06 '13 at 13:59
  • The problem you have here is that your xml file is not actually an xml file. Are you sure the file is actually as you have shown us, or is the text contained within an element, such as `...`? – Tim C Aug 06 '13 at 14:19
  • sorry for miscommunication, I updated the complete file. – kumar Aug 06 '13 at 14:27

3 Answers3

4

If your are stuck with XSLT 1.0 you can use this:

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

 <!--String replace template-->
 <xsl:template name="removeline">
    <xsl:param name="string" />
    <xsl:choose>
    <xsl:when test="contains($string,'remove')">
        <xsl:variable name="before">
        <xsl:value-of select="substring-before($string,'remove')"/>
        </xsl:variable>
        <xsl:variable name="after">
        <xsl:value-of select="substring-after($string,'remove')"/>
        </xsl:variable>
        <xsl:value-of select="substring($before,1, string-length($before) - 12)"/>
        <xsl:call-template name="removeline">
            <xsl:with-param name="string" select="$after" />
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$string" />
    </xsl:otherwise>
    </xsl:choose>
 </xsl:template>

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

  <!-- copy text nodes, and apply removeline template  -->
  <xsl:template match="text()" >

     <!-- create empty string for match -->
     <xsl:variable name="empty_string"/>

     <xsl:if test="normalize-space(.) != $empty_string">
            <xsl:call-template name="removeline">
        <xsl:with-param name="string" select="normalize-space(.)"/>
        </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

You can see three templates here. The first one is a string function replacement for XSLT 1.0, that has none. It is based on one found in several places of the net. You can find a more generalist implementation of it in https://stackoverflow.com/a/7523245/2657945.

The second and the third templates output all nodes and attributtes in the document as it gets them, making a special case of text nodes,that are processed with the first template. This part is based in what is found in https://stackoverflow.com/a/427983/2657945.

The output is like this (using xsltproc, in linux):

<server>
  <mbean code="org.jboss.varia.property.SystemPropertiesService" name="abc.props:type=Service,name=abcprop">
    <attribute name="Properties">abc.def.ghi=123 ghi.klm.nop=123 qrst.tuv.wxy=123 zab.cde.fgh=123  rst.uvw.xyz=123 abc.tuv.nop=123 ajc.dzf.goi=123</attribute>
  </mbean>
</server>

It is the most aproximate result I'm able to produce with you xml sample, so depending on your file and format you may need to tweak it some more.

Community
  • 1
  • 1
MACN
  • 196
  • 7
  • 13
  • thanks for xslt 1.0 version, since i dont have any contraint using 2.0 I will better go with Martin's solution. – kumar Aug 06 '13 at 18:36
2

With XSLT 2.0 you can use the replace function on the text nodes you want to manipulate:

<xsl:stylesheet version="2.0" exclude-result-prefixes="xs"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="attribute[@name = 'Properties']/text()">
      <xsl:value-of select="replace(., '^.*remove.*$\n*', '', 'm')"/>
    </xsl:template>

</xsl:stylesheet>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
0

XSLT 1.0 has only very limited string handling function, so there is no easy way to do what you ask with pure XSLT.

The best way would be to use some extension function written in a different language - most XSLT processor can define and call such extension functions: Xalan-Java, Saxon, .NET

As an alternative consider not using XSLT at all - considering that your problem is basically string matching and not XML-related: just load the XML and process the string using your favorite programming language.

MiMo
  • 11,793
  • 1
  • 33
  • 48
  • hmmm thats the constraint, since i am using most of my other functionalities using xslt, I had to use some bash or awk to process just for this one functionality and its a maven project. – kumar Aug 06 '13 at 14:43
  • @phani: are you sure it is XSLT 1.0? I came across examples of Maven XSLT using 2.0 – MiMo Aug 06 '13 at 15:28
  • I belive maven also supports 1.0, thats what i have been doing. – kumar Aug 06 '13 at 15:44
  • Any idea how to do it with SAXON? – kumar Aug 06 '13 at 16:04
  • I added a link to the relevant Saxon documentation - but if you can use XSLT 2.0 you probably won't need extensions - XSLT 2.0 supports regular expressions and in general has a much better string handling. – MiMo Aug 06 '13 at 16:09
  • Can you give me an example with xslt 2.0? – kumar Aug 06 '13 at 16:10