tags:

views:

184

answers:

3

want to make a comma-delimited string from a list of 3 possible attributes of an element.

I have found a thread here: http://stackoverflow.com/questions/798269/xslt-concat-string-remove-last-comma

that describes how to build a comma-delimited string from elements. I want to do the same thing with a list of attributes.

From the following element:

<myElement attr1="Don't report this one" attr2="value1" attr3="value2" attr4="value3" />

I would like to produce a string that reads: "value1,value2,value3"

One other caveat: attr2 thru attr4 may or may not have values but, if they do have values, they will go in order. So, attr4 will not have a value if attr3 does not. attr3 will not have a value if attr2 does not. So, for an attribute to have a value, the one before it in the attribute list must have a value.

How can I modify the code in the solution to the thread linked to above so that it is attribute-centric instead of element-centric?

Thanks in advance for whatever help you can provide.

+2  A: 

This is easy in principe, but only if it is really clear which attribute you want to exclude. Since attributes are not by definition ordered in XML (in contrast the elements), you need to say how the attribute(s) to skip can be identified.

Edit: Regarding the attribute order, XML section 3.1 says:

Note that the order of attribute specifications in a start-tag or empty-element tag is not significant.

That said, something like this should do the trick (adjust the [] condition as you see fit):

<xsl:template match="myElement">
  <xsl:for-each select="@*[position()!=1]">
    <xsl:value-of select="." />
    <xsl:if test="position()!=last()">,</xsl:if>
  </xsl:for-each>
</xsl:template>
Lucero
fantastic!pointing the for-each loop at "@", then using position to determine which attribute I am looking at is the key thing. I have not seen that before, I don't think.
rogdawg
+1 ... but there's a little typo in ` match="myElement> missing the closing quotes.
Filburt
@rogdawg, this is a technique I use quite often, also when copying attributes with modifications etc.@Filburt, thanks, fixed.
Lucero
+3  A: 

In XSLT 2.0 it is as easy as

<xsl:template match="myElement">
  <xsl:value-of select="@* except @att1" separator=","/>
</xsl:template>
Martin Honnen
+1 for the XSLT 2.0 sample. Unfortunately XSLT 2.0 processors are very rare...
Lucero
thanks for your response. I wish ASP.NET supported XSLT 2.0. But as of yet [and as far as I know] it doesn't. I have come across several things that would be far easier in XSLT 2.0.Thanks, though.
rogdawg
Saxon 9 comes in two versions, a Java version and a .NET version, so it is possible to use XSLT 2.0 in .NET applications respectively in ASP.NET applications, see http://www.xmlplease.com/saxonaspnet and of course the Saxon documentation on http://www.saxonica.com/ on how to use Saxon with .NET applications.
Martin Honnen
@Martin, yeah I do know of Saxon (and the .NET port of it), but is there anything else around?
Lucero
There are other XSLT 2.0 processors, on Windows there is AltovaXML tools, see http://www.altova.com/altovaxml.html. Then there is Gestalt, see http://gestalt.sourceforge.net/.And both IBM and Intel have released an XSLT 2.0 processor to be available as an extension pack to their web server application pack (Websphere for IBM, not sure what Intel's product name is). Intel's is only a beta. So there are more options by now although some of them tie you to some product, as in the case of IBM and Intel.
Martin Honnen
+1  A: 

I would appreciate Lucero's answer .. He definitely has nailed it ..
Well, Here is one more code which truncates attribute attr1, which appears at any positions other than 1 in attribute list.
scenario like this::

<myElement attr2="value1" attr3="value2" attr4="value3" attr1="Don't report this one" />

Here is the XSLT code .. ::

  <xsl:template match="myElement">
    <xsl:for-each select="@*[name()!='attr1']">
      <xsl:value-of select="." />
      <xsl:if test="position()!=last()">,</xsl:if>
    </xsl:for-each>
  </xsl:template>

The output will be:

value1,value2,value3

If you wish to omit more than one attribute say .. attr1 and attr2 ..

  <xsl:template match="myElement">
    <xsl:for-each select="@*[name()!='attr1' and name()!='attr2']">
      <xsl:value-of select="." />
      <xsl:if test="position()!=last()">,</xsl:if>
    </xsl:for-each>
  </xsl:template>

The corresponding output will be:

value2,value3
infant programmer
Comparing `name()` is not recommended because it breaks if someone uses prefixes. So it's better to either do use the `self::` axis or a combination of `local-name()` and `namespace-uri()`.
Lucero
Well. I am not really familiar with prefixes and namespace-uri .. things .. soon, I'll learn about them and then I will definitely edit my answer .. thanx for valuable advice @Lucero .. :-)
infant programmer