I have an xml document following this overall pattern:
<A b="c" d="e" f="g" h="i">
<!-- plenty of children -->
</A>
I would like to copy the A
node with only some of it's attributes:
<A b="c" f="g">
<!-- some of the children -->
</A>
Other answers here have come close to solving my challenge but have not quite been enough:
- This answer gave me a solution that would work but would be very long: https://stackoverflow.com/a/672962/145978
- so I could go with
<xsl:copy-of select="@*[(name()!='d') or (name()!='h']"/>
but my actual attribute list is very long. - I did try finding a 'is-a-member-of-this-list'-type function but got lost rather quickly.
- so I could go with
- This answer seemed to discuss a Whitelist but I am apparently not smart enough to be able to apply it to attribute selection: https://stackoverflow.com/a/5790798/145978
Please help
Generally, if you want to drop something from the input, write an empty template for what you want to remove:
and another, non-empty template for what you want to keep:
and then simply apply templates normally:
That's all, this does the right thing already.
Hint: If you have an identity template in place in your stylesheet and no other changes to
<A>
are necessary then you don't even need that third template.The whitelist solution that you linked uses an embedded document containing the list of elements that should be preserved. You can have a similar one for your attributes:
It can be loaded and parsed using the
document('')
function, and you can store it in a variable to make it easier to refer to it:Now the
$keep
variable contains the names of all the attributes in the list. The asterisk represents the<xsl:stylesheet>
element, since the argument passed todocument()
is an empty string, which causes it to load from the current document.Then you can test if the names of arbitrary atrributes match any one that is in the
$keep
node-set:The others you copy using an identity transformation.
Here is a full stylesheet for the example you provided:
If you're using XSLT 2.0, you can use a sequence. If you put it in an
xsl:param
instead of anxsl:variable
, you can define the whitelist at runtime (if you want).Example:
XSLT 2.0