I need to incorporate all permutations when testing the possible values (separated by a space) for a variable in xsl:when
.
在测试xsl:when中的变量的可能值(用空格分隔)时,我需要合并所有排列。
For example:
<xsl:when test="$var='A B C'
or $var='B A C'
or $var='...'
or ...>
<xsl:value-of select="X+Z"/>
Is there a smart and simple way of doing it?
有一种聪明而简单的方法吗?
6 个解决方案
#1
1
Instead of trying to generate all permutations, I would test if all values of the source are present in the target, and that both source and target contain the same number of values.
我将测试源的所有值是否存在于目标中,并且源和目标包含相同数量的值,而不是尝试生成所有排列。
This is a bit verbose in XSLT 1.0, but still:
这在XSLT 1.0中有点冗长,但仍然:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="source" select="'A B C'"/>
<xsl:variable name="target" select="'B A C'"/>
<xsl:variable name="every-source-in-target">
<xsl:call-template name="every-source-in-target">
<xsl:with-param name="source" select="$source"/>
<xsl:with-param name="target" select="$target"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="count-source" select="string-length(translate($source, translate($source, $delimiter, ''), ''))" />
<xsl:variable name="count-target" select="string-length(translate($target, translate($target, $delimiter, ''), ''))" />
<xsl:template match="/">
<result>
<xsl:if test="$every-source-in-target='true' and $count-source=$count-target ">MATCH</xsl:if>
</result>
</xsl:template>
<xsl:template name="every-source-in-target">
<xsl:param name="source"/>
<xsl:param name="target"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($source, $delimiter), $delimiter)" />
<xsl:choose>
<xsl:when test="not(contains(concat($delimiter, $target, $delimiter), concat($delimiter, $token, $delimiter)))">
<xsl:value-of select="false()"/>
</xsl:when>
<xsl:when test="contains($source, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="every-source-in-target">
<xsl:with-param name="source" select="substring-after($source, $delimiter)"/>
<xsl:with-param name="target" select="$target"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="true()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that some assumptions are being made here: for example, "A B B C"
and "B A A C"
will return a match. If that's not acceptable, then the next best thing, IMHO, would be to sort the values before comparing the sets:
请注意,这里有一些假设:例如,“A B B C”和“B A A C”将返回匹配。如果那是不可接受的,那么下一个最好的东西,恕我直言,就是在比较集合之前对值进行排序:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="source" select="'A B C'"/>
<xsl:variable name="target" select="'B A C'"/>
<xsl:variable name="sorted-source">
<xsl:call-template name="sort-list">
<xsl:with-param name="list" select="$source"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="sorted-target">
<xsl:call-template name="sort-list">
<xsl:with-param name="list" select="$target"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<result>
<xsl:if test="$sorted-source=$sorted-target">MATCH</xsl:if>
</result>
</xsl:template>
<xsl:template name="sort-list">
<xsl:param name="list"/>
<!-- tokenize the list -->
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="$list"/>
</xsl:call-template>
</xsl:variable>
<!-- re-assemble the list in alphabetic order -->
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:sort select="." data-type="text" order="ascending"/>
<xsl:value-of select="."/>
<xsl:if test="position()!=last">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:if test="$token">
<token>
<xsl:value-of select="$token"/>
</token>
</xsl:if>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
#2
1
If all the strings are valid names, then a neat 2.0 solution would be to turn the strings into attributes and use deep-equals():
如果所有字符串都是有效名称,那么一个简洁的2.0解决方案是将字符串转换为属性并使用deep-equals():
deep-equal(f:to-atts(source), f:to-atts(target))
<xsl:function f:to-atts as="xs:boolean">
<xsl:param name="in" as="xs:string">
<e>
<xsl:for-each select="tokenize($in, ' ')">
<xsl:attribute name="." select="0"/>
</xsl:for-each>
</e>
</xsl:function>
Note this eliminates duplicates: "A A" will be equal to "A". You haven't said whether this is desirable.
注意这消除了重复:“A A”将等于“A”。你还没有说这是否可取。
#3
1
The quick & easy way of doing this is to first define a variable that puts your delimiter at the beginning and end like this:
快速简便的方法是首先定义一个变量,将分隔符放在开头和结尾,如下所示:
<xsl:variable name="tempVar" select="concat(' ',$var,' ')"/>
then simply use
然后简单地使用
<xsl:when test="contains($tempVar,' A ') and
contains($tempVar, ' B ') and
contains($tempVar, ' C ')">
<xsl:value-of select="X+Z"/>
</xsl:when>
Putting a space at the beginning & end of tempVar
just means that all values are surrounded by spaces whether at the beginning/end or not, making it possible to just check for the presence of each value with a space at each side.
在tempVar的开头和结尾放置一个空格只意味着所有值都被空格包围,无论是在开头还是结尾,这样就可以只检查每个值的存在,每边都有一个空格。
You could do without the variable of course, you'd just need to repeat the concat expression three times in your test
attribute.
你当然可以不使用变量,你只需要在test属性中重复三次concat表达式。
#4
1
An XSLT 2.0 solution that avoids sorting and is more efficient: O(N)
vs. O(N*log(N))
XSLT 2.0解决方案,可避免排序并提高效率:O(N)与O(N * log(N))
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output method="text"/>
<xsl:key name="kAllItems" match="x" use="."/>
<xsl:param name="pData">
<x>A</x>
<x>B</x>
<x>C</x>
</xsl:param>
<xsl:template match="v">
(<xsl:value-of select="."/>) ==> <xsl:sequence
select="my:exactPremutation(., $pData)"/>
</xsl:template>
<xsl:function name="my:exactPremutation" as="xs:boolean">
<xsl:param name="pInput" as="xs:string"/>
<xsl:param name="pDataItems" as="document-node()"/>
<xsl:variable name="vNumDataItems" select="count($pDataItems/*)"/>
<xsl:variable name="vMatches" as="xs:integer*">
<xsl:for-each-group select="tokenize($pInput, '\s+')" group-by=".">
<xsl:variable name="vMatchedDataItem"
select="key('kAllItems', current-grouping-key(), $pDataItems)"/>
<xsl:sequence select="1[not(current-group()[2]) and $vMatchedDataItem]"/>
<xsl:sequence select="($vNumDataItems +1)[not($vMatchedDataItem)]"/>
</xsl:for-each-group>
</xsl:variable>
<xsl:sequence select="sum($vMatches) eq $vNumDataItems"/>
</xsl:function>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
将此转换应用于以下XML文档时:
<t>
<!-- Correct -->
<v>A B C</v>
<v>A C B</v>
<v>B A C</v>
<v>B C A</v>
<v>C A B</v>
<v>C B A</v>
<!-- Incorrect -->
<v>C A C</v>
<v>A B</v>
<v></v>
<v>A B C D</v>
</t>
the wanted, correct result is produced:
产生了想要的正确结果:
(A B C) ==> true (A C B) ==> true (B A C) ==> true (B C A) ==> true (C A B) ==> true (C B A) ==> true (C A C) ==> false (A B) ==> false () ==> false (A B C D) ==> false
Note: The linear efficiency estimation assumes that an efficient (such as hash-table based) implementation of grouping is used by the XSLT processor.
注意:线性效率估计假定XSLT处理器使用有效(例如基于散列表)的分组实现。
#5
1
An efficient solution for verifying that a single string is an exact permutation of a given set of strings is presented here: https://*.com/a/35497256/36305
这里给出了一个有效的解决方案,用于验证单个字符串是给定字符串集的精确排列:https://*.com/a/35497256/36305
The following verifies that the children of the top element of the source XML document are all possible permutations of a given set of strings.
以下内容验证源XML文档的top元素的子元素是给定字符串集的所有可能排列。
Rules:
- A single space must be used as delimiter.
- Any string in the given string-set doesn't contain a space.
- The value of any child of the top element of the XML document must be a normalized string -- should only contain inner single spaces, each delimiting two adjacent non-space-containing substrings.
必须使用单个空格作为分隔符。
给定字符串集中的任何字符串都不包含空格。
XML文档顶部元素的任何子元素的值必须是规范化的字符串 - 应该只包含内部单个空格,每个空格分隔两个相邻的非包含空格的子字符串。
The transformation produces the string "Valid input." if the string values of /*/*
(the children of the top element of the XML document) represent every possible permutation of the items of the given string-set -- and exactly once.
转换生成字符串“有效输入”。如果/ * / *的字符串值(XML文档的顶部元素的子元素)表示给定字符串集的项的每个可能的排列 - 并且恰好一次。
If this is not so, the transformation terminates with diagnostic messages explaining the exact violation found.
如果不是这样,则转换将终止,并显示诊断消息,说明找到的确切违规。
The items of the string-set are represented as children of an XML element that is the value of the global parameter, named prtfData
字符串集的项表示为XML元素的子元素,该元素是全局参数的值,名为prtfData
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="prtfData">
<v>A</v>
<v>B</v>
<v>C</v>
</xsl:param>
<xsl:variable name="vData" select="document('')/*/xsl:param[@name = 'prtfData']/*"/>
<xsl:variable name="vnumItems" select="count($vData)"/>
<xsl:variable name="vTotalLength" select="string-length($prtfData) + $vnumItems -1"/>
<xsl:variable name="vnumPermutations">
<xsl:call-template name="factorial">
<xsl:with-param name="pN" select="$vnumItems"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="/*">
<xsl:if test="not(count(*) = $vnumPermutations)">
<xsl:message terminate="yes">
Error: The count of /*/* is not <xsl:value-of select="$vnumPermutations"/>
</xsl:message>
</xsl:if>
<xsl:if test="v[not(string-length() = $vTotalLength)]">
<xsl:message terminate="yes">
The input item "<xsl:value-of select="v[not(string-length() = $vTotalLength)]"/>" <xsl:text/>
<xsl:text/>has string-length not-equal to <xsl:text/>
<xsl:value-of select="$vTotalLength"/>
</xsl:message>
</xsl:if>
<xsl:variable name="vInput" select="/*/*"/>
<xsl:for-each select="$vData">
<xsl:variable name="vPaddedItem" select="concat(' ', ., ' ')"/>
<xsl:if test="$vInput[not(contains(concat(' ', ., ' '), $vPaddedItem))]">
<xsl:message terminate="yes">
Error: The data item "<xsl:value-of select="."/>" isn't contained in <xsl:text/>
<xsl:value-of select="$vInput[not(contains(concat(' ', ., ' '), $vPaddedItem))]"/>.
</xsl:message>
</xsl:if>
</xsl:for-each>
<xsl:if test="$vInput[. = preceding-sibling::* or . = following-sibling::*]">
<xsl:message terminate="yes">
Error: Some data items are equal. Not all permutations represented.
</xsl:message>
</xsl:if>
Valid input.
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="pN" select="1"/>
<xsl:param name="pResult" select="1"/>
<xsl:choose>
<xsl:when test="not($pN > 0)">
<xsl:value-of select="$pResult"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="factorial">
<xsl:with-param name="pN" select="$pN -1"/>
<xsl:with-param name="pResult" select="$pN * $pResult"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
将此转换应用于以下XML文档时:
<t>
<v>C B A</v>
<v>C A B</v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the result is:
结果是:
Valid input.
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v> C A B </v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
The input item " C A B " has string-length not-equal to 5
输入项“C A B”的字符串长度不等于5
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v>C C B</v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: The data item "A" isn't contained in C C B.
错误:数据项“A”未包含在C C B中。
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v>C C B</v>
<v>B A C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: The count of
/*/*
is not 6错误:/ * / *的计数不是6
Finally, when the transformation is applied on this XML document:
最后,当对此XML文档应用转换时:
<t>
<v>C B A</v>
<v>C A B</v>
<v>C A B</v>
<v>B A C</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: Some data items are equal. Not all permutations represented.
错误:某些数据项相同。并非所有排列都代表。
#6
0
Here's a simple XPath 1.0 solution:
这是一个简单的XPath 1.0解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="x" select="'B A C'"/>
<xsl:variable name="y" select="'A B C'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="string-length($x) = string-length($y)
and translate($x, $y, '') = ''">
<xsl:message>Same</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:message>Different</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that this assumes unique, single-char values being permuted.
请注意,这假定要置换唯一的单字符值。
#1
1
Instead of trying to generate all permutations, I would test if all values of the source are present in the target, and that both source and target contain the same number of values.
我将测试源的所有值是否存在于目标中,并且源和目标包含相同数量的值,而不是尝试生成所有排列。
This is a bit verbose in XSLT 1.0, but still:
这在XSLT 1.0中有点冗长,但仍然:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="source" select="'A B C'"/>
<xsl:variable name="target" select="'B A C'"/>
<xsl:variable name="every-source-in-target">
<xsl:call-template name="every-source-in-target">
<xsl:with-param name="source" select="$source"/>
<xsl:with-param name="target" select="$target"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="count-source" select="string-length(translate($source, translate($source, $delimiter, ''), ''))" />
<xsl:variable name="count-target" select="string-length(translate($target, translate($target, $delimiter, ''), ''))" />
<xsl:template match="/">
<result>
<xsl:if test="$every-source-in-target='true' and $count-source=$count-target ">MATCH</xsl:if>
</result>
</xsl:template>
<xsl:template name="every-source-in-target">
<xsl:param name="source"/>
<xsl:param name="target"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($source, $delimiter), $delimiter)" />
<xsl:choose>
<xsl:when test="not(contains(concat($delimiter, $target, $delimiter), concat($delimiter, $token, $delimiter)))">
<xsl:value-of select="false()"/>
</xsl:when>
<xsl:when test="contains($source, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="every-source-in-target">
<xsl:with-param name="source" select="substring-after($source, $delimiter)"/>
<xsl:with-param name="target" select="$target"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="true()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that some assumptions are being made here: for example, "A B B C"
and "B A A C"
will return a match. If that's not acceptable, then the next best thing, IMHO, would be to sort the values before comparing the sets:
请注意,这里有一些假设:例如,“A B B C”和“B A A C”将返回匹配。如果那是不可接受的,那么下一个最好的东西,恕我直言,就是在比较集合之前对值进行排序:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="source" select="'A B C'"/>
<xsl:variable name="target" select="'B A C'"/>
<xsl:variable name="sorted-source">
<xsl:call-template name="sort-list">
<xsl:with-param name="list" select="$source"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="sorted-target">
<xsl:call-template name="sort-list">
<xsl:with-param name="list" select="$target"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<result>
<xsl:if test="$sorted-source=$sorted-target">MATCH</xsl:if>
</result>
</xsl:template>
<xsl:template name="sort-list">
<xsl:param name="list"/>
<!-- tokenize the list -->
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="$list"/>
</xsl:call-template>
</xsl:variable>
<!-- re-assemble the list in alphabetic order -->
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:sort select="." data-type="text" order="ascending"/>
<xsl:value-of select="."/>
<xsl:if test="position()!=last">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:if test="$token">
<token>
<xsl:value-of select="$token"/>
</token>
</xsl:if>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
#2
1
If all the strings are valid names, then a neat 2.0 solution would be to turn the strings into attributes and use deep-equals():
如果所有字符串都是有效名称,那么一个简洁的2.0解决方案是将字符串转换为属性并使用deep-equals():
deep-equal(f:to-atts(source), f:to-atts(target))
<xsl:function f:to-atts as="xs:boolean">
<xsl:param name="in" as="xs:string">
<e>
<xsl:for-each select="tokenize($in, ' ')">
<xsl:attribute name="." select="0"/>
</xsl:for-each>
</e>
</xsl:function>
Note this eliminates duplicates: "A A" will be equal to "A". You haven't said whether this is desirable.
注意这消除了重复:“A A”将等于“A”。你还没有说这是否可取。
#3
1
The quick & easy way of doing this is to first define a variable that puts your delimiter at the beginning and end like this:
快速简便的方法是首先定义一个变量,将分隔符放在开头和结尾,如下所示:
<xsl:variable name="tempVar" select="concat(' ',$var,' ')"/>
then simply use
然后简单地使用
<xsl:when test="contains($tempVar,' A ') and
contains($tempVar, ' B ') and
contains($tempVar, ' C ')">
<xsl:value-of select="X+Z"/>
</xsl:when>
Putting a space at the beginning & end of tempVar
just means that all values are surrounded by spaces whether at the beginning/end or not, making it possible to just check for the presence of each value with a space at each side.
在tempVar的开头和结尾放置一个空格只意味着所有值都被空格包围,无论是在开头还是结尾,这样就可以只检查每个值的存在,每边都有一个空格。
You could do without the variable of course, you'd just need to repeat the concat expression three times in your test
attribute.
你当然可以不使用变量,你只需要在test属性中重复三次concat表达式。
#4
1
An XSLT 2.0 solution that avoids sorting and is more efficient: O(N)
vs. O(N*log(N))
XSLT 2.0解决方案,可避免排序并提高效率:O(N)与O(N * log(N))
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output method="text"/>
<xsl:key name="kAllItems" match="x" use="."/>
<xsl:param name="pData">
<x>A</x>
<x>B</x>
<x>C</x>
</xsl:param>
<xsl:template match="v">
(<xsl:value-of select="."/>) ==> <xsl:sequence
select="my:exactPremutation(., $pData)"/>
</xsl:template>
<xsl:function name="my:exactPremutation" as="xs:boolean">
<xsl:param name="pInput" as="xs:string"/>
<xsl:param name="pDataItems" as="document-node()"/>
<xsl:variable name="vNumDataItems" select="count($pDataItems/*)"/>
<xsl:variable name="vMatches" as="xs:integer*">
<xsl:for-each-group select="tokenize($pInput, '\s+')" group-by=".">
<xsl:variable name="vMatchedDataItem"
select="key('kAllItems', current-grouping-key(), $pDataItems)"/>
<xsl:sequence select="1[not(current-group()[2]) and $vMatchedDataItem]"/>
<xsl:sequence select="($vNumDataItems +1)[not($vMatchedDataItem)]"/>
</xsl:for-each-group>
</xsl:variable>
<xsl:sequence select="sum($vMatches) eq $vNumDataItems"/>
</xsl:function>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
将此转换应用于以下XML文档时:
<t>
<!-- Correct -->
<v>A B C</v>
<v>A C B</v>
<v>B A C</v>
<v>B C A</v>
<v>C A B</v>
<v>C B A</v>
<!-- Incorrect -->
<v>C A C</v>
<v>A B</v>
<v></v>
<v>A B C D</v>
</t>
the wanted, correct result is produced:
产生了想要的正确结果:
(A B C) ==> true (A C B) ==> true (B A C) ==> true (B C A) ==> true (C A B) ==> true (C B A) ==> true (C A C) ==> false (A B) ==> false () ==> false (A B C D) ==> false
Note: The linear efficiency estimation assumes that an efficient (such as hash-table based) implementation of grouping is used by the XSLT processor.
注意:线性效率估计假定XSLT处理器使用有效(例如基于散列表)的分组实现。
#5
1
An efficient solution for verifying that a single string is an exact permutation of a given set of strings is presented here: https://*.com/a/35497256/36305
这里给出了一个有效的解决方案,用于验证单个字符串是给定字符串集的精确排列:https://*.com/a/35497256/36305
The following verifies that the children of the top element of the source XML document are all possible permutations of a given set of strings.
以下内容验证源XML文档的top元素的子元素是给定字符串集的所有可能排列。
Rules:
- A single space must be used as delimiter.
- Any string in the given string-set doesn't contain a space.
- The value of any child of the top element of the XML document must be a normalized string -- should only contain inner single spaces, each delimiting two adjacent non-space-containing substrings.
必须使用单个空格作为分隔符。
给定字符串集中的任何字符串都不包含空格。
XML文档顶部元素的任何子元素的值必须是规范化的字符串 - 应该只包含内部单个空格,每个空格分隔两个相邻的非包含空格的子字符串。
The transformation produces the string "Valid input." if the string values of /*/*
(the children of the top element of the XML document) represent every possible permutation of the items of the given string-set -- and exactly once.
转换生成字符串“有效输入”。如果/ * / *的字符串值(XML文档的顶部元素的子元素)表示给定字符串集的项的每个可能的排列 - 并且恰好一次。
If this is not so, the transformation terminates with diagnostic messages explaining the exact violation found.
如果不是这样,则转换将终止,并显示诊断消息,说明找到的确切违规。
The items of the string-set are represented as children of an XML element that is the value of the global parameter, named prtfData
字符串集的项表示为XML元素的子元素,该元素是全局参数的值,名为prtfData
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="prtfData">
<v>A</v>
<v>B</v>
<v>C</v>
</xsl:param>
<xsl:variable name="vData" select="document('')/*/xsl:param[@name = 'prtfData']/*"/>
<xsl:variable name="vnumItems" select="count($vData)"/>
<xsl:variable name="vTotalLength" select="string-length($prtfData) + $vnumItems -1"/>
<xsl:variable name="vnumPermutations">
<xsl:call-template name="factorial">
<xsl:with-param name="pN" select="$vnumItems"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="/*">
<xsl:if test="not(count(*) = $vnumPermutations)">
<xsl:message terminate="yes">
Error: The count of /*/* is not <xsl:value-of select="$vnumPermutations"/>
</xsl:message>
</xsl:if>
<xsl:if test="v[not(string-length() = $vTotalLength)]">
<xsl:message terminate="yes">
The input item "<xsl:value-of select="v[not(string-length() = $vTotalLength)]"/>" <xsl:text/>
<xsl:text/>has string-length not-equal to <xsl:text/>
<xsl:value-of select="$vTotalLength"/>
</xsl:message>
</xsl:if>
<xsl:variable name="vInput" select="/*/*"/>
<xsl:for-each select="$vData">
<xsl:variable name="vPaddedItem" select="concat(' ', ., ' ')"/>
<xsl:if test="$vInput[not(contains(concat(' ', ., ' '), $vPaddedItem))]">
<xsl:message terminate="yes">
Error: The data item "<xsl:value-of select="."/>" isn't contained in <xsl:text/>
<xsl:value-of select="$vInput[not(contains(concat(' ', ., ' '), $vPaddedItem))]"/>.
</xsl:message>
</xsl:if>
</xsl:for-each>
<xsl:if test="$vInput[. = preceding-sibling::* or . = following-sibling::*]">
<xsl:message terminate="yes">
Error: Some data items are equal. Not all permutations represented.
</xsl:message>
</xsl:if>
Valid input.
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="pN" select="1"/>
<xsl:param name="pResult" select="1"/>
<xsl:choose>
<xsl:when test="not($pN > 0)">
<xsl:value-of select="$pResult"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="factorial">
<xsl:with-param name="pN" select="$pN -1"/>
<xsl:with-param name="pResult" select="$pN * $pResult"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
将此转换应用于以下XML文档时:
<t>
<v>C B A</v>
<v>C A B</v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the result is:
结果是:
Valid input.
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v> C A B </v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
The input item " C A B " has string-length not-equal to 5
输入项“C A B”的字符串长度不等于5
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v>C C B</v>
<v>B A C</v>
<v>B C A</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: The data item "A" isn't contained in C C B.
错误:数据项“A”未包含在C C B中。
When applied on this XML document:
应用于此XML文档时:
<t>
<v>C B A</v>
<v>C C B</v>
<v>B A C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: The count of
/*/*
is not 6错误:/ * / *的计数不是6
Finally, when the transformation is applied on this XML document:
最后,当对此XML文档应用转换时:
<t>
<v>C B A</v>
<v>C A B</v>
<v>C A B</v>
<v>B A C</v>
<v>A C B</v>
<v>A B C</v>
</t>
the processing is terminated with this message:
处理以此消息终止:
Error: Some data items are equal. Not all permutations represented.
错误:某些数据项相同。并非所有排列都代表。
#6
0
Here's a simple XPath 1.0 solution:
这是一个简单的XPath 1.0解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="x" select="'B A C'"/>
<xsl:variable name="y" select="'A B C'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="string-length($x) = string-length($y)
and translate($x, $y, '') = ''">
<xsl:message>Same</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:message>Different</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that this assumes unique, single-char values being permuted.
请注意,这假定要置换唯一的单字符值。