Jump to content

Selecting Unique Elements


awitt

Recommended Posts

Hey guys, I need to pull out all elements of data, within an XML, that are unique. Specifically, it's an XML full of school closings around the state. The problem is, sometimes there are duplicate records in the XML. Every record has an id attribute, and even those are the same for the duplicate records. I want to prove/disprove uniqueness using those ids associated with each element. Here's a sample of the XML file:

<closings> 	<county name="Adams"> 		<announcement id="1" onn="1" wbns="0"> 			<location>Ohio Valley Local Schools</location> 			<status>Closed</status> 			<source>172.19.16.33</source> 			<creationtime>Jan 28 2009 05:02AM</creationtime> 			<expiretime>Jan 28 2009 01:00PM</expiretime> 		</announcement> 		<announcement id="2443" onn="1" wbns="0"> 			<location>Snow Emergency</location> 			<status>Level 3 Snow Emergency</status> 			<source>172.19.16.33</source> 			<creationtime>Jan 28 2009 09:19AM</creationtime> 			<expiretime>Jan 28 2009 07:00PM</expiretime> 		</announcement> 	</county>	<county name="Wood"> 		<announcement id="602" onn="1" wbns="0"> 			<location>Bowling Green City Schools</location> 			<status>Closed</status> 			<source>172.19.16.8</source> 			<creationtime>Jan 28 2009 06:50AM</creationtime> 			<expiretime>Jan 28 2009 01:00PM</expiretime> 		</announcement> 		<announcement [b]id="603"[/b] onn="1" wbns="0"> 			<location>Eastwood Local Schools</location> 			<status>Closed</status> 			<source>172.19.16.8</source> 			<creationtime>Jan 28 2009 06:53AM</creationtime> 			<expiretime>Jan 28 2009 01:00PM</expiretime> 		</announcement> 		<announcement [b]id="603"[/b] onn="1" wbns="0"> 			<location>Eastwood Local Schools</location> 			<status>Closed</status> 			<source>172.19.16.8</source> 			<creationtime>Jan 28 2009 06:53AM</creationtime> 			<expiretime>Jan 28 2009 01:00PM</expiretime> 		</announcement> 		<announcement id="604" onn="1" wbns="0"> 			<location>Elmwood Local Schools</location> 			<status>Closed</status> 			<source>172.19.16.8</source> 			<creationtime>Jan 28 2009 06:53AM</creationtime> 			<expiretime>Jan 28 2009 01:00PM</expiretime> 		</announcement>	</county></closings>

And here's what I have for my XSLT (at least as far as going through and selecting nodes):

	   	<xsl:for-each select="closings/county/announcement">	<tr>		<xsl:attribute name="id">row_<xsl:value-of select="./@id" /></xsl:attribute>			<td class="county_row">				<xsl:value-of select="../@name" />			</td>			<td class="location_row">				<xsl:attribute name="id">row_<xsl:value-of select="./@id" />_loc</xsl:attribute>				<xsl:value-of select="location" />			</td>			<td class="status_row">				<xsl:value-of select="status" />			</td>	</tr></xsl:for-each>

Can anyone help me with figuring this out? Oh, and follow this link. It's some kind of solution to the problem i am facing, but I honestly just don't know enough of the XML technologies to make sense of it in my context. It may help those of you who are more learned than I, though.

Link to comment
Share on other sites

From the comments in that article, maybe define a variable like this:<xsl:variable name="unique-list" select="closings/county/announcement/@id[not(.=following::@id)]" />And then a loop like this:<xsl:for-each select="$unique-list">...</xsl:for-each>

Link to comment
Share on other sites

Hmm, I tried doing that, but a couple of problems occur:1.) The XSLT engine yells at me - it says, "ERROR: Error in expression closings/county/announcement/@id[not(.=following::@id)]: Unexpected token [@] after axis name; SystemID: ...", which, through a 'lil trial and error, I found meant that the '@' symbol in the brackets and braces ( [not(.=following::@id)] ) had a symbol that wasn't supposed to be there. 2.) Then it transformed, but the resulting html page was devoid of any data from the XML.So, that didn't work, unfortunately. Does it maybe have to do with the fact that we're trying to select distinct nodes based on an attribute?

Link to comment
Share on other sites

Okay, so I think I'm using it correctly now, but it still produces the duplicate results, and I don't know how it's doing that or how to make this do what i want.

	   			<xsl:variable name="unique-list" 	   				select="closings/county/announcement[not(@id=following::closings/county/announcement/@id)]" />	   			<xsl:for-each select="$unique-list">				<tr>					<xsl:attribute name="id">row_<xsl:value-of select="./@id" /></xsl:attribute>					<td class="county_row">						<xsl:value-of select="../@name" />					</td>					<td class="location_row">						<xsl:attribute name="id">row_<xsl:value-of select="./@id" />_loc</xsl:attribute>						<xsl:value-of select="location" />					</td>					<td class="status_row">						<xsl:value-of select="status" />					</td>				</tr>	   			</xsl:for-each>

Link to comment
Share on other sites

Alrighty - for those of you who had been following this topic - here's the working code that will let you select a distinct (i.e. unique) set of nodes:

	<xsl:variable name="unique-list" 	select="closings/county/announcement[not(@id=following::announcement/@id)]" />	<xsl:for-each select="$unique-list">		var closing1=new closing("<xsl:value-of select="./@id" />", "<xsl:value-of select="../@name" />", 			"<xsl:value-of select="location" />", "<xsl:value-of select="status" />");		table_for_sc[i]=closing1;		i++;	</xsl:for-each>

Now, a couple things to note:1.) This is a solution for attributes. It'd be slightly different if you were trying to select unique locations, for example. If that was your aim, though, this is what you'd be looking at: <xsl:variable name="unique-list" select="closings/county/announcement/location[not(.=following::location)]" />2.) There are some missing variable declarations in the snippets above, but in the actual code from which they came, they are defined and instantiated.And now for the best explanation that I am capable of giving: So, you start by creating a variable in which to store the "new," or filtered, result set (<xsl:variable name="unique-list" ...). Secondly, you tell it what you want put into that variable (... select="closings/county/announcement ...). But wait, that still doesn't make sure that the selected values are unique! Well, that's where one's knowledge of XPath comes in real handy (and my knowledge of XPath is paltry, by the way, so be aware of that as I try my best to explain its role here). So now you've got this piece of code left: [not(@id=following::announcement/@id)] . This is the line that makes sure the elements/nodes you select are, in fact, unique. So, you told it to select all of the announcements in the first part of that line, and then you limit those announcements to only those that are not already in the aforementioned variable that we created to store this information. Now, the reason that you do not specify more of a path inside those brackets is because you already told the XSLT engine to go "into" the announcements node, so that's where you're at when you specify the elements not to pull out. So, since you're already in an announcement node, all you have to do is tell it to test against the id attribute of the announcement element (announcement/@id). After you get all that working, then you go about business as normal, but making sure to pull out further selections from the variable you created in which to store all the unique elements of that XML file: <xsl:for-each select="$unique-list"> . Well, I hope I explained that well enough; my understanding of the topic is quite limited, but I am learning all this as I go, so I feel okay about myself.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...