XSLT:如何找到节点的唯一 children 计数?
XSLT: How to find the count of unique children of a node?
我的 XML 看起来像这样:
<foo>
<bar name="a">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="b">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="c">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
</foo>
我正在编写一个需要像这样运行的 XSL:如果所有 baz
children 都相同,则 doSomething
否则 doSomethingElse
。我当前的节点是foo
.
我是 XSLT 的新手,我知道 XSL 中的条件。现在看起来像这样:
<xsl:template match="foo">
<xsl:choose>
<xsl:when test="[My condition]">
doSomething()
</xsl:when>
<xsl:otherwise>
doSomethingElse()
</xsl:otherwise>
</xsl:choose>
</xsl:template>
在当前示例中,它应该 doSomething()
因为所有 baz
元素都相同。
如果我找出唯一的 baz
元素的数量,我可以测试它是否等于一。如果是,那我就doSomething()
else doSomethingElse()
我该如何实施? MyCondition
应该是什么?
PS: 我的 XSL 版本是 1.0
If all the baz
children are same then doSomething
else
doSomethingElse
. My current node is foo
.
这令人困惑,因为:
baz
不是foo
的child仁;
- 您的标题说“查找唯一 children 的计数”- 但事实并非如此
必须找到它才能知道它们是否相同。
试试这样的东西:
<xsl:template match="foo">
<xsl:variable name="first-baz" select="(bar/baz)[1]" />
<xsl:choose>
<xsl:when test="bar/baz[date!=$first-baz/date or time!=$first-baz/time]">
<!-- THEY ARE NOT ALL SAME -->
</xsl:when>
<xsl:otherwise>
<!-- THEY ARE ALL SAME -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
请注意,这假设每个 baz
都有一个 date
和一个 time
。否则你需要测试 not(date=$first-baz/date)
等
另请参阅:
http://www.jenitennison.com/xslt/grouping/muenchian.html
已添加:
Now, assuming all the bar/baz
elements have the same tags (not
necessarily date
and time
but say a
, b
and c
), what would be
the test attribute for that case?
这使得它变得更加复杂。你仍然可以构造一个密钥:
<xsl:key name="first-baz" match="foo/bar[1]/baz[1]/*" use="name()" />
然后进行测试:
<xsl:when test="bar/baz/*[. != key('first-baz', name())]">
如果 baz
中的任何 child 存在其 string-value 不同于第一个 child 的同名节点,则此 returns 为真=13=].
请注意,此处定义的密钥是 document-wide。如果你想将测试限制在当前的 foo
祖先,那么你必须在键中包含它的 id。
如果您想以通用方式执行此操作,那么您实际上是在将 XSLT 1.0 的功能扩展到其设计限制之外。但这是可以完成的。
编写一个名为 deep-equal 的命名模板,它将两个元素作为其参数,returns 一个包含字符 "F" 的字符串当且仅当它们不相等(出于您的目的)。
它可能看起来像这样:
<xsl:template name="deep-equal">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:choose>
<xsl:when test="local-name(a) != local-name(b)">F</xsl:when>
<xsl:when test="namespace-uri(a) != namespace-uri(b)">F</xsl:when>
<xsl:when test="normalize-space(a) != normalize-space(b)">F</xsl:when>
<xsl:when test="count(a/*) != count(b/*)">F</xsl:when>
<xsl:otherwise>
<xsl:variable name="diffs">
<xsl:for-each select="*">
<xsl:variable name="position" select="position()"/>
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="."/>
<xsl:with-param name="b" select="$b/*[$position]"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
将此应用到所有相关的元素对:
<xsl:variable name="comparison">
<xsl:for-each select="baz[position() >= 2]">
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="../baz[1]"/>
<xsl:with-param name="b" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
测试结果是否包含"F":
<xsl:if test="contains($comparison, 'F')">...</xsl:if>
我的 XML 看起来像这样:
<foo>
<bar name="a">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="b">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
<bar name="c">
<baz name="xyz">
<time>2</time>
<date>3</date>
</baz>
</bar>
</foo>
我正在编写一个需要像这样运行的 XSL:如果所有 baz
children 都相同,则 doSomething
否则 doSomethingElse
。我当前的节点是foo
.
我是 XSLT 的新手,我知道 XSL 中的条件。现在看起来像这样:
<xsl:template match="foo">
<xsl:choose>
<xsl:when test="[My condition]">
doSomething()
</xsl:when>
<xsl:otherwise>
doSomethingElse()
</xsl:otherwise>
</xsl:choose>
</xsl:template>
在当前示例中,它应该 doSomething()
因为所有 baz
元素都相同。
如果我找出唯一的 baz
元素的数量,我可以测试它是否等于一。如果是,那我就doSomething()
else doSomethingElse()
我该如何实施? MyCondition
应该是什么?
PS: 我的 XSL 版本是 1.0
If all the
baz
children are same thendoSomething
elsedoSomethingElse
. My current node isfoo
.
这令人困惑,因为:
baz
不是foo
的child仁;- 您的标题说“查找唯一 children 的计数”- 但事实并非如此 必须找到它才能知道它们是否相同。
试试这样的东西:
<xsl:template match="foo">
<xsl:variable name="first-baz" select="(bar/baz)[1]" />
<xsl:choose>
<xsl:when test="bar/baz[date!=$first-baz/date or time!=$first-baz/time]">
<!-- THEY ARE NOT ALL SAME -->
</xsl:when>
<xsl:otherwise>
<!-- THEY ARE ALL SAME -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
请注意,这假设每个 baz
都有一个 date
和一个 time
。否则你需要测试 not(date=$first-baz/date)
等
另请参阅: http://www.jenitennison.com/xslt/grouping/muenchian.html
已添加:
Now, assuming all the
bar/baz
elements have the same tags (not necessarilydate
andtime
but saya
,b
andc
), what would be the test attribute for that case?
这使得它变得更加复杂。你仍然可以构造一个密钥:
<xsl:key name="first-baz" match="foo/bar[1]/baz[1]/*" use="name()" />
然后进行测试:
<xsl:when test="bar/baz/*[. != key('first-baz', name())]">
如果 baz
中的任何 child 存在其 string-value 不同于第一个 child 的同名节点,则此 returns 为真=13=].
请注意,此处定义的密钥是 document-wide。如果你想将测试限制在当前的 foo
祖先,那么你必须在键中包含它的 id。
如果您想以通用方式执行此操作,那么您实际上是在将 XSLT 1.0 的功能扩展到其设计限制之外。但这是可以完成的。
编写一个名为 deep-equal 的命名模板,它将两个元素作为其参数,returns 一个包含字符 "F" 的字符串当且仅当它们不相等(出于您的目的)。
它可能看起来像这样:
<xsl:template name="deep-equal">
<xsl:param name="a"/>
<xsl:param name="b"/>
<xsl:choose>
<xsl:when test="local-name(a) != local-name(b)">F</xsl:when>
<xsl:when test="namespace-uri(a) != namespace-uri(b)">F</xsl:when>
<xsl:when test="normalize-space(a) != normalize-space(b)">F</xsl:when>
<xsl:when test="count(a/*) != count(b/*)">F</xsl:when>
<xsl:otherwise>
<xsl:variable name="diffs">
<xsl:for-each select="*">
<xsl:variable name="position" select="position()"/>
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="."/>
<xsl:with-param name="b" select="$b/*[$position]"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
将此应用到所有相关的元素对:
<xsl:variable name="comparison">
<xsl:for-each select="baz[position() >= 2]">
<xsl:call-template name="deep-equal">
<xsl:with-param name="a" select="../baz[1]"/>
<xsl:with-param name="b" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
测试结果是否包含"F":
<xsl:if test="contains($comparison, 'F')">...</xsl:if>