[英]XSLT 2.0 Compare sequence of attribute values to variable
I have elements such as 我有诸如
<elem attr1="value1 someValue" attr2="value2 someOtherValue"/>
elements with a variable amount of attributes that each have a variable amount of values. 具有可变数量的属性的元素,每个元素具有可变数量的值。
Some of these attributes' names and some of their values are saved in variables beforehand and the elements are checked against these variables. 这些属性的名称和它们的某些值会预先保存在变量中,并根据这些变量检查元素。
I need to check if the element has attributes specified in that variable (which I got working) and if for each attribute, at least one of its values is one of the values specified in another variable. 我需要检查元素是否具有在该变量中指定的属性(我已经开始使用该属性),并且对于每个属性,至少其值之一是在另一个变量中指定的值之一。
So if the variable contains " Value1 Value2
" (or more values) 因此,如果变量包含“ Value1 Value2
”(或更多值)
The element 元素
<elem attr1="Value1 SomeValue" attr2="Value1 someOtherValue AthirdValue" attr3="value2 otherValue"/>
meets the requirements (provided that attr1, attr2 and attr3 are the correct attribute names, which I check before), but element: 满足要求(前提是attr1,attr2和attr3是正确的属性名称,我之前已经对其进行过检查),但是元素:
<elem attr1="Value1 SomeValue" attr2="anything someOtherValue" attr3="value otherValue"/>
doesn't meet the requirements, because one of the attributes has no value that is contained in the variable ( attr2
: neither anything
nor someOtherValue
are specified in the variable). 不符合要求,因为其中一个属性没有包含在变量中的值( attr2
:在变量中未指定anything
或someOtherValue
)。
I tried tokenizing the values, but then the elemens are considered correct even if only one attribute has one of the correct values. 我尝试对值进行标记,但是即使只有一个属性具有正确的值之一,这些元素也被认为是正确的。 I need to make sure, all of the attributes have at least one of the correct values. 我需要确保所有属性至少具有正确的值之一。
Help and tips highly appreciated! 帮助和提示高度赞赏!
EDIT: 编辑:
The way the values of the variable are 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 at the filters elements above, the elems can look like this: 查看上面的filter元素,elems可能如下所示:
<elem/> <!-- no attribute -->
<elem someattr="somevalue"/> <!-- some irrelevant attribute -->
<elem attr1="value1"/> <!-- one of the attributes -->
<elem attr1="value1" attr2="value"/> <!-- two of the attributes -->
So the @name
attribute of the filters
element specifies the name of the attribute on the elem
element and the @value
attribute of the filters element specifies the value that that attribute must have in order to meet the requirements. 因此, filters
元素的@name
属性指定elem
元素上的属性的名称, filters
元素的@value
属性指定该属性必须具有的值才能满足要求。
SOLUTION (adapted from answer post) 解决方案(改编自答案)
<xsl:when test="count(@*[local-name() = $filterNames]) > 1">
<!-- element has more then one 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">
<!-- at least one attribute doesnt have any of the required values -->
</xsl:when>
<xsl:otherwise>
<!-- all attributes have at least one of the 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 is all a bit abstract, but to demonstrate a principle, let us have the following: 这有点抽象,但是为了展示一个原理,让我们有以下几点:
XML 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 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 is at least one attribute that, after tokenizing, does not contain any token that matches one of the values in the $values variable. 当至少一个属性在标记化之后不包含任何与$ values变量中的值之一匹配的标记时,返回true。
In response to your modified requirements, I believe this should work: 根据您修改后的要求,我认为这应该可行:
XSLT 2.0 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 could probably be streamlined a bit, but first I would like to know if it provides the correct answers. 可能可以简化一下,但是首先我想知道它是否提供正确的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.