xml - XSLT 2.0 Compare sequence of attribute values to variable -
i have elements such as
<elem attr1="value1 somevalue" attr2="value2 someothervalue"/>
elements variable amount of attributes each have variable amount of values.
some of these attributes' names , of values saved in variables beforehand , elements checked against these variables.
i need check if element has attributes specified in variable (which got working) , if each attribute, @ least 1 of values 1 of values specified in variable.
so if variable contains "value1 value2
" (or more values)
the element
<elem attr1="value1 somevalue" attr2="value1 someothervalue athirdvalue" attr3="value2 othervalue"/>
meets requirements (provided attr1, attr2 , attr3 correct attribute names, check before), element:
<elem attr1="value1 somevalue" attr2="anything someothervalue" attr3="value othervalue"/>
doesn't meet requirements, because 1 of attributes has no value contained in variable (attr2
: neither anything
nor someothervalue
specified in variable).
i tried tokenizing values, elemens considered correct if 1 attribute has 1 of correct values. need make sure, of attributes have @ least 1 of correct values.
help , tips highly appreciated!
edit:
the way values of variable obtained:
<xsl:variable name="filtername" select="$somedoc//someelem[@id = $curid]//filters/@value"/>
the other document:
<?xml version="1.0"/> <doc> <filters name="attr1" value="value1"/> <filters name="attr2" value="value2"/> <filters name="attr3" value="value2"/> </doc> **edit 2:**
looking @ filters elements above, elems can this:
<elem/> <!-- no attribute --> <elem someattr="somevalue"/> <!-- irrelevant attribute --> <elem attr1="value1"/> <!-- 1 of attributes --> <elem attr1="value1" attr2="value"/> <!-- 2 of attributes -->
so @name
attribute of filters
element specifies name of attribute on elem
element , @value
attribute of filters element specifies value that attribute must have in order meet requirements.
solution (adapted answer post)
<xsl:when test="count(@*[local-name() = $filternames]) > 1"> <!-- element has more 1 filter attribute --> <xsl:variable name="currentfiltervalues"> <xsl:value-of select="$filtervalues"/> </xsl:variable> <xsl:variable name="attributenamesofcurrentelement"> <xsl:value-of select="@*[local-name() = $filternames]/fn:local-name()"/> </xsl:variable> <xsl:variable name="errors"> <xsl:for-each select="tokenize($attributenamesofcurrentelement, '\s+')"> <xsl:variable name="currentname" select="."/> <xsl:variable name="currentvalue" select="$currentelement/@*[fn:local-name() = $currentname]"/> <xsl:if test="not(tokenize($currentvalue, '\s+') = tokenize($currentfiltervalues, ' '))"> <error/> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:choose> <xsl:when test="$errors/error"> <!-- @ least 1 attribute doesnt have of required values --> </xsl:when> <xsl:otherwise> <!-- attributes have @ least 1 of required values --> <xsl:copy> <xsl:apply-templates select="$currentelement_2/@*"/> <xsl:if test="child::*"> <xsl:for-each select="child::*"> <xsl:call-template name="recurse"> <xsl:with-param name="filternames" select="$filternames"/> <xsl:with-param name="filtervalues" select="$filtervalues"/> <xsl:with-param name="filtertype" select="$filtertype"/> <xsl:with-param name="currentelement_2" select="."/> </xsl:call-template> </xsl:for-each> </xsl:if> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:when>
this bit abstract, demonstrate principle, let have following:
xml
<root> <elem attr1="alpha charlie" attr2="delta alpha echo" attr3="foxtrot bravo golf"/> <elem attr1="alpha charlie" attr2="hotel delta" attr3="bravo india"/> </root>
xslt 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/> <xsl:variable name="values" select="('alpha', 'bravo')"/> <xsl:template match="/root"> <xsl:copy> <xsl:apply-templates select="elem"/> </xsl:copy> </xsl:template> <xsl:template match="elem"> <xsl:copy> <xsl:choose> <xsl:when test="@*[not(tokenize(., ' ')=$values)]"> <xsl:text>no</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>yes</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> </xsl:stylesheet>
result
<?xml version="1.0" encoding="utf-8"?> <root> <elem>yes</elem> <elem>no</elem> </root>
explanation
the test:
test="@*[not(tokenize(., ' ')=$values)]"
returns true when there @ least 1 attribute that, after tokenizing, not contain token matches 1 of values in $values variable.
edit
in response modified requirements, believe should work:
xslt 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/> <xsl:variable name="filter-doc" select="document('filter.xml')"/> <xsl:key name="filter-by-name" match="filters" use="@name" /> <xsl:template match="/root"> <xsl:copy> <xsl:apply-templates select="elem"/> </xsl:copy> </xsl:template> <xsl:template match="elem"> <xsl:variable name="strikes"> <xsl:for-each select="@*[key('filter-by-name', name(), $filter-doc)]"> <xsl:variable name="values" select="key('filter-by-name', name(), $filter-doc)/@value" /> <xsl:if test="not(tokenize(., ' ')=$values)"> <strike/> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:copy> <xsl:choose> <xsl:when test="$strikes/strike"> <xsl:text>no</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>yes</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> </xsl:stylesheet>
this streamlined bit, first know if provides correct answers.
Comments
Post a Comment