XML Editor
Sign up for a WebBoard account Sign Up Keyword Search Search More Options... Options
Chat Rooms Chat Help Help News News Log in to WebBoard Log in Not Logged in
Show tree view Topic
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Postnext
dave garciaSubject: How to remove specific text entries from element content?
Author: dave garcia
Date: 05 Dec 2007 02:54 PM
Greetings,

Using XSL I need to match on and remove specific values in the element content shown below:

<Property Name="ObjList">V1S1|V1S2|V1S3|V1S4|V1S5|V1S6</Property>
<Property Name="XPos">400|1400|350|1000|1000|250</Property>
<Property Name="YPos">300|300|500|600|700|800</Property>

So for example using/passing_in the following element as a key:

<OBJ>V1S3</OBJ>

How in XSL can I lookup and remove the matching element in ObjList, XPos, and YPos? Such that the XML I write back out looks like the following:

<Property Name="ObjList">V1S1|V1S2|V1S4|V1S5|V1S6</Property>
<Property Name="XPos">400|1400|1000|1000|250</Property>
<Property Name="YPos">300|300|600|700|800</Property>

You can assume the entries I want to remove in XPos and YPos are always in the same position/order as what is in ObjList (in this case they were the 3rd entry in the content/string as was V1S3 in ObjList).

TIA,

David

Postnext
Alberto MassariSubject: How to remove specific text entries from element content?
Author: Alberto Massari
Date: 06 Dec 2007 09:48 AM
Hi Dav,
these template should perform what you need

<xsl:template name="remove_if">
<xsl:param name="to_remove"/>
<xsl:param name="properties"/>
<xsl:param name="list"/>

<xsl:if test="string-length($list) &gt; 0">

<xsl:choose>
<xsl:when test="contains($list, '|')">
<xsl:if test="substring-before($properties, '|') != $to_remove"><xsl:value-of select="substring-before($list, '|')"/>|</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$properties != $to_remove"><xsl:value-of select="$list"/></xsl:if>
</xsl:otherwise>
</xsl:choose>

<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="$to_remove"/>
<xsl:with-param name="properties" select="substring-after($properties,'|')"/>
<xsl:with-param name="list" select="substring-after($list, '|')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

It should be invoked once for each list to process, specifying both the list of IDs and the values to filter, like this:

<xsl:template match="/">
<Property Name='ObjList'>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="'V1S3'"/>
<xsl:with-param name="properties" select="Property[@Name='ObjList']"/>
<xsl:with-param name="list" select="Property[@Name='ObjList']"/>
</xsl:call-template>
</Property>
<Property Name='XPos'>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="'V1S3'"/>
<xsl:with-param name="properties" select="Property[@Name='ObjList']"/>
<xsl:with-param name="list" select="Property[@Name='XPos']"/>
</xsl:call-template>
</Property>
<Property Name='YPos'>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="'V1S3'"/>
<xsl:with-param name="properties" select="Property[@Name='ObjList']"/>
<xsl:with-param name="list" select="Property[@Name='YPos']"/>
</xsl:call-template>
</Property>

</xsl:template>

Hope this helps,
Alberto

Postnext
dave garciaSubject: How to remove specific text entries from element content?
Author: dave garcia
Date: 06 Dec 2007 09:54 AM
Thank you Alberto. Does this assume XSLT V2.0? Unfortunately I am currently tied to V1.0 and cannot upgrade until my everyone on my team does and we are not doing that for a while. Thanks again.

Postnext
Alberto MassariSubject: How to remove specific text entries from element content?
Author: Alberto Massari
Date: 06 Dec 2007 09:57 AM
No, it only uses XSLT 1.0 instructions.

Alberto

Postnext
dave garciaSubject: How to remove specific text entries from element content?
Author: dave garcia
Date: 06 Dec 2007 10:08 AM
Great, Thanks! :)

Postnext
dave garciaSubject: How to remove specific text entries from element content?
Author: dave garcia
Date: 26 Dec 2007 07:55 AM
Originally Posted: 26 Dec 2007 07:54 AM
Hi Alberto,

I tried this solution and technically it works fine, thank you! the problem I am running into is that when I try to implement this functionality into an existing stylesheet I have, the performance is very slow. I should have expressed my requirements better I apologize, I will try to do that below.

What would work better for me is instead of passing in single value to remove as shown below:

<xsl:with-param name="to_remove" select="'V1S3'"/>

is to pass in ALL values to be removed in a list. What further complicates this however is that the values to be removed, live in an existing list of values where only SOME of them are candidates to be removed. Currently I attempt to execute all this as follows:

<xsl:template match="/">

<xsl:for-each select="Export/*/Record[contains(@Type,'notation')][Property[@Name='notationText' and contains(text(),'MSG:')]]">
<xsl:variable name="notationID" select="@Identifier"/>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="$notationID"/>
<xsl:with-param name="properties" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='ObjList']"/>
<xsl:with-param name="list" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='ObjList']"/>
</xsl:call-template>
</xsl:for-each>

</xsl:template>

For a 4MB XML document this takes about 10 minutes to run and it does not seem to remove the items as I had hoped. I am guessing the performance problem is becuase on each recursive call to "remove_if" it has to pass the entire document in on paramters 2 and 3; in addition to walking through the same document in the for-loop. My thought was instead of using a for-loop, pass in all the values for to_remove at once in a list and get rid of the for-loop.

The problem I see with that, since only SOME of the values qualify for removal (as indicated in the condition in the for-loop), I would first have to create a node-set() which would be hard becuase the the number of items to remove would change each time (or are dynamic). Maybe I could create a variable some how with members in it that contains the items to remove with global scope then use the document() function to get at the values somehow? Remember I have to do all this in XSLT V1.0, I realize in V2.0 this would probably be a lot easier but don't have much choice in this matter.

Thanks In Advance,

Dave

Postnext
Alberto MassariSubject: How to remove specific text entries from element content?
Author: Alberto Massari
Date: 27 Dec 2007 05:26 AM
Hi Dave,
I think your problem is that you are passing more data than you need to the template: I guess that an XPath like /Export/*/Record[@Type='ContainerView']/Property[@Name='ObjList'] will match a lot of properties, even unrelated to the Record you just identified.
Unfortunately, only you know the relation between the Record having a @Type containing "notation" and the Record with a @Type equal to "ContainerView", so it's up to you to find how to substitute the "/Export/*/" in the xsl:with-param instructions....

Alberto

Posttop
dave garciaSubject: How to remove specific text entries from element content?
Author: dave garcia
Date: 07 Jan 2008 08:19 AM
Originally Posted: 07 Jan 2008 08:10 AM
Alberto, thanks again for the template you originally provided me, by expanding on it below is the final solution that now processes multiple string values which can be removed from a series of strings. I am hoping at some point I can move to XSLT V2.0 so I can harness the power of that version as my understanding is that this would have been much easier to do in 2.0, for now I have to stay on 1.0 with the rest of my team. Thanks again.

Ciao,

David

Sample Input:

<?xml version="1.0" encoding="UTF-8"?>
<Export>
<foo>
<Record Type="ContainerView">
<Property Name="ObjList">V1S1|V1S2|V1S3|V1A1|V1A2|V1A3|V1A4|V1A5</Property>
<Property Name="XPos">400|600|800|10|310|510|520|710</Property>
<Property Name="YPos">80|30|70|10|50|90|60|20</Property>
</Record>
</foo>
</Export>

Final Solution/Stylesheet:

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

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

<xsl:variable name="remove_multi">
<xsl:for-each select="Export/*/Record[contains(@Type,'notation')][Property[@Name='notationText' and (contains(text(),'MSG:') or contains(text(),'UNSUPPORTED'))]]">
<xsl:variable name="notationID" select="@Identifier"/>
<xsl:value-of select="$notationID"/>
<xsl:text>|</xsl:text>
</xsl:for-each>
</xsl:variable>

<xsl:template match="/">

<xsl:variable name="properties" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='ObjList']"/>
<xsl:variable name="ObjList" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='ObjList']"/>
<xsl:variable name="XPos" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='XPos']"/>
<xsl:variable name="YPos" select="/Export/*/Record[@Type='ContainerView']/Property[@Name='YPos']"/>

<Property Name='ObjList'>
<xsl:choose>
<xsl:when test="string-length($remove_multi) &gt; 0">
<xsl:call-template name="remove_multiple">
<xsl:with-param name="remlist" select="$remove_multi"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$ObjList"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$ObjList"/>
</xsl:otherwise>
</xsl:choose>
</Property>

<Property Name='XPos'>
<xsl:choose>
<xsl:when test="string-length($remove_multi) &gt; 0">
<xsl:call-template name="remove_multiple">
<xsl:with-param name="remlist" select="$remove_multi"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$XPos"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$XPos"/>
</xsl:otherwise>
</xsl:choose>
</Property>

<Property Name='YPos'>
<xsl:choose>
<xsl:when test="string-length($remove_multi) &gt; 0">
<xsl:call-template name="remove_multiple">
<xsl:with-param name="remlist" select="$remove_multi"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$YPos"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$YPos"/>
</xsl:otherwise>
</xsl:choose>
</Property>
</xsl:template>

<xsl:template name="remove_multiple">
<xsl:param name="remlist"/>
<xsl:param name="properties"/>
<xsl:param name="list"/>

<xsl:variable name="proplist" select="$properties"/>

<xsl:variable name="removed_this">
<xsl:choose>
<xsl:when test="contains($remlist, '|')">
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="substring-before($remlist, '|')"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$list"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="$remlist"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$list"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="removed_props">
<xsl:choose>
<xsl:when test="contains($remlist, '|')">
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="substring-before($remlist, '|')"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$proplist"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="$remlist"/>
<xsl:with-param name="properties" select="$properties"/>
<xsl:with-param name="list" select="$proplist"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:choose>
<xsl:when test="string-length(substring-after($remlist, '|')) &gt; 0">
<xsl:call-template name="remove_multiple">
<xsl:with-param name="remlist" select="substring-after($remlist, '|')"/>
<xsl:with-param name="properties" select="$removed_props"/>
<xsl:with-param name="list" select="$removed_this"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="ln" select="string-length($removed_this)"/>
<xsl:variable name= "removed_that" select="substring($removed_this,1,$ln - 1)"/>
<xsl:value-of select="$removed_that"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="remove_if">
<xsl:param name="to_remove"/>
<xsl:param name="properties"/>
<xsl:param name="list"/>

<xsl:if test="string-length($list) &gt; 0">
<xsl:choose>
<xsl:when test="contains($list, '|')"><xsl:if test="substring-before($properties, '|') != $to_remove"><xsl:value-of select="substring-before($list, '|')"/>|</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$properties != $to_remove"><xsl:value-of select="$list"/></xsl:if>
</xsl:otherwise>
</xsl:choose>

<xsl:call-template name="remove_if">
<xsl:with-param name="to_remove" select="$to_remove"/>
<xsl:with-param name="properties" select="substring-after($properties,'|')"/>
<xsl:with-param name="list" select="substring-after($list, '|')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

 
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Download A Free Trial of Stylus Studio 6 XML Professional Edition Today! Powered by Stylus Studio, the world's leading XML IDE for XML, XSLT, XQuery, XML Schema, DTD, XPath, WSDL, XHTML, SQL/XML, and XML Mapping!  
go

Log In Options

Site Map | Privacy Policy | Terms of Use | Trademarks
Stylus Scoop XML Newsletter:
W3C Member
Stylus Studio® and DataDirect XQuery ™are from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2016 All Rights Reserved.