tnapolitano
asked on
XML XSLT return values for duplicate/repeating elements
Very new to XML so excuse if I don't have my terms right yet.
I've got some XML looks like this:
<port protocol="tcp" portid="21"><state state="open" /><service name="ftp" method="table" conf="3" /></port>
<port protocol="tcp" portid="53"><state state="open" /><service name="domain" method="table" conf="3" /></port>
<port protocol="tcp" portid="80"><state state="open" /><service name="http" method="table" conf="3" /></port>
<port protocol="tcp" portid="135"><state state="open" /><service name="msrpc" method="table" conf="3" /></port>
I'm want to return all values for "service name" and display in a single cell of a table (i.e., ftp, domain, http, msrpc).
All I get with <td><xsl:value-of select="ports/port/service /@name" /></td> is the first value, "ftp".
What am I trying to do (by that I mean, what is the operation called)? And, better yet, how do I do it?
I've got some XML looks like this:
<port protocol="tcp" portid="21"><state state="open" /><service name="ftp" method="table" conf="3" /></port>
<port protocol="tcp" portid="53"><state state="open" /><service name="domain" method="table" conf="3" /></port>
<port protocol="tcp" portid="80"><state state="open" /><service name="http" method="table" conf="3" /></port>
<port protocol="tcp" portid="135"><state state="open" /><service name="msrpc" method="table" conf="3" /></port>
I'm want to return all values for "service name" and display in a single cell of a table (i.e., ftp, domain, http, msrpc).
All I get with <td><xsl:value-of select="ports/port/service
What am I trying to do (by that I mean, what is the operation called)? And, better yet, how do I do it?
tnapolitano,
I have templates (rules based nature of XSLT) for the different elements
and inside one template I push nodesets to the templates with apply-templates
like that I create a very hierarchical model for processing the XML
the stylesheet starts working with the template match="/"
There I create the html and body tag and in the middle of that I push all the chilnodes to the templates
The element "ports" gets picked up by the template for "ports"
and there I create a table and push the port nodes to the templates
As you see now, I have created a table inside the html/body
the template match="port" will be executed for every port element inside ports
this is how I create a number of rows , one for each port
If you would want only one row, this is what you would do
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="ports">
<table border="1">
<tr>
<xsl:apply-templates select="port"/>
</tr>
</table>
</xsl:template>
<xsl:template match="port">
<td><xsl:value-of select="service/@name" /></td>
</xsl:template>
</xsl:stylesheet>
take your time to understand the examples
note that this way of programming XSLT is superior over using for-each loops
cheers
Geert
I have templates (rules based nature of XSLT) for the different elements
and inside one template I push nodesets to the templates with apply-templates
like that I create a very hierarchical model for processing the XML
the stylesheet starts working with the template match="/"
There I create the html and body tag and in the middle of that I push all the chilnodes to the templates
The element "ports" gets picked up by the template for "ports"
and there I create a table and push the port nodes to the templates
As you see now, I have created a table inside the html/body
the template match="port" will be executed for every port element inside ports
this is how I create a number of rows , one for each port
If you would want only one row, this is what you would do
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="ports">
<table border="1">
<tr>
<xsl:apply-templates select="port"/>
</tr>
</table>
</xsl:template>
<xsl:template match="port">
<td><xsl:value-of select="service/@name" /></td>
</xsl:template>
</xsl:stylesheet>
take your time to understand the examples
note that this way of programming XSLT is superior over using for-each loops
cheers
Geert
tnapolitano,
from your title I assume that you only want unique values
here would be the XSLT that ignores a duplicate value "ftp" and only shows it want
I do this by being selective on the port-nodes that I push to the port template
(it should not have a value of service/@name that a preceding port element has)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="ports">
<table border="1">
<tr>
<xsl:apply-templates select="port[not(service/@ name = preceding::port/service/@n ame)]"/>
</tr>
</table>
</xsl:template>
<xsl:template match="port">
<td><xsl:value-of select="service/@name" /></td>
</xsl:template>
</xsl:stylesheet>
I hope this is enough to get you started
Geert
from your title I assume that you only want unique values
here would be the XSLT that ignores a duplicate value "ftp" and only shows it want
I do this by being selective on the port-nodes that I push to the port template
(it should not have a value of service/@name that a preceding port element has)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="ports">
<table border="1">
<tr>
<xsl:apply-templates select="port[not(service/@
</tr>
</table>
</xsl:template>
<xsl:template match="port">
<td><xsl:value-of select="service/@name" /></td>
</xsl:template>
</xsl:stylesheet>
I hope this is enough to get you started
Geert
ASKER
Gertone, thanks for all that. Let me try this out and I'll get back to you.
ASKER
Great answer, gertone. Just what I needed. Both the code to get the job done and explanations of what's going on. Thanks again.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I accept this answer. You can close it out.
This XSLT will make you a table with all the values
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="ports">
<table border="1">
<xsl:apply-templates select="port"/>
</table>
</xsl:template>
<xsl:template match="port">
<tr>
<td><xsl:value-of select="service/@name" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
Cheers!