【问题标题】:XSL Ambiguous rule match and adjacent groupingXSL 模糊规则匹配和相邻分组
【发布时间】:2018-04-03 11:21:58
【问题描述】:

我上周已经发布了有关相邻组合并的问题。 我很新,可能有一些我不明白的东西......

所以我有一个模板,可以将相邻组与其 CSS 类名合并。

<xsl:template name="fusionElements">
<xsl:param name="classFusion" />
<xsl:copy>
  <xsl:apply-templates select="@*" />
  <xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="@class=$classFusion">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <xsl:for-each-group select="current-group()" group-by="concat(node-name(.), '|', $classFusion)">
          <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="current-group()/node()" />
          </xsl:element>
        </xsl:for-each-group>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:copy>

然后我像这样调用模板。我正在搜索具有多个 spans 且具有相同 CSS 类的 p 节点。

<xsl:template match="p[contains(@class, 'Normal')][count(./span[contains(@class, 'USous-article')])>0]">
<xsl:call-template name="fusionElements">
  <xsl:with-param name="classFusion" select="./span[1][contains(@class,'USous-article')]/@class" />
</xsl:call-template>

<xsl:template match="p[contains(@class, 'Normal')][count(./span[contains(@class, 'UCitation')])>0]">
<xsl:call-template name="fusionElements">
  <xsl:with-param name="classFusion" select="./span[1][contains(@class,'UCitation')]/@class" />
</xsl:call-template>

它可以正常工作,除非我在同一 p 内有具有不同 CSS 类的相邻节点

<p class="Normal">
        <a name="Art10Prg1"><!--anchor--></a>
        <span class="USous-article Default">§</span>
        <span class="USous-article Default"> </span>
        <span class="USous-article Default">1er</span>
        <span class="USous-article Default"> </span>
        <span class="USous-article Default">-</span> 
        <span class="UCitation Default">a)</span>
        <span class="UCitation Default"> </span>
Some text!</p>

我想要做的是:

<p class="Normal">
    <a name="Art10Prg1"><!--anchor--></a>
    <span class="USous-article Default">§ 1er -</span>
    <span class="UCitation Default">a) </span>
Some text!</p>

我理解错误(两个不同的模板匹配同一个节点)但我不知道如何解决问题。

Warning XTDE0540: Ambiguous rule match for /html/body[1]/div[2]/p[219] Matches both p span "UCitation" and p span "USous-article"

【问题讨论】:

  • 首先,您会收到警告而不是错误。至于解决它,你想发生什么,应用这两个具有更高优先级的模板之一?您可以设置priority 属性一个xsl:template 例如&lt;xsl:template match="p[contains(@class, 'Normal')][count(./span[contains(@class, 'UCitation')])&gt;0]" priority="5"&gt;。如果您这样做,警告将消失,处理器仅应用具有最高优先级的模板(而不是使用文档顺序中的最后一个)。
  • 我尝试应用优先级,但这意味着某些标签不会被合并。这就是为什么我开始问我的解决方案是否真的很好。但我不知道没有优先权怎么办……
  • 我认为需要更改方法以实现该分组,但是从一个示例和一些不工作的代码(这是合并的规则)中有点难以理解。 xsltfiddle.liberty-development.net/pPqsHSZ 中的代码对您的示例 sn-p 进行了正确的合并,但在 spans 之间丢失了空格,并且按照当前编写的方式,还将合并相邻的 span class="foo" 不包含您正在寻找的两个类。我认为您需要重新表述问题并更详细地解释代码必须有多灵活以及输入可以有哪些变化。

标签: xml xslt xslt-2.0


【解决方案1】:

我认为您可以将要检查的各种类定义为字符串序列,然后您可以使用一个分组结构(至少在我们有复合键的 XSLT 3 中):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:param name="classes-to-merge" as="xs:string*" select="'USous-article', 'UCitation'"/>

  <xsl:output method="html" indent="yes" html-version="5.0"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="p[contains-token(@class, 'Normal') and span[some $class in $classes-to-merge satisfies contains-token(@class, $class)]]">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:for-each-group select="node() except text()[not(normalize-space())]" composite="yes" group-adjacent="node-name(), some $class in $classes-to-merge satisfies contains-token(@class, $class), @class">
              <xsl:choose>
                  <xsl:when test="not(empty(current-grouping-key()[1])) and current-grouping-key()[2] and not(empty(current-grouping-key()[3]))">
                      <xsl:copy>
                          <xsl:apply-templates select="@*, current-group()/node()"/>
                      </xsl:copy>
                  </xsl:when>
                  <xsl:otherwise>
                      <xsl:apply-templates select="current-group()"/>
                  </xsl:otherwise>
              </xsl:choose>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

这改变了

<p class="Normal">
        <a name="Art10Prg1"><!--anchor--></a>
        <span class="USous-article Default">§</span>
        <span class="USous-article Default"> </span>
        <span class="USous-article Default">1er</span>
        <span class="USous-article Default"> </span>
        <span class="USous-article Default">-</span>
        <span class="foo">foo 1</span>
        <span class="foo">foo 2</span>
        <span class="UCitation Default">a)</span>
        <span class="UCitation Default"> </span>
Some text!</p>

进入

<p class="Normal"><a name="Art10Prg1">
      <!--anchor--></a><span class="USous-article Default">§ 1er -</span><span class="foo">foo 1</span><span class="foo">foo 2</span><span class="UCitation Default">a) </span>
   Some text!
</p>

https://xsltfiddle.liberty-development.net/pPqsHSZ/1

使用 XSLT 2,您可以尝试使用嵌套的 for-each-groups,也可以连接分组键组件以模拟复合键:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf">

    <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="mf:contains-token" as="xs:boolean">
        <xsl:param name="input" as="xs:string*"/>
        <xsl:param name="token" as="xs:string"/>
        <xsl:variable name="tokenized-input" as="xs:string*"
            select="for $i in $input return tokenize($i, '\s+')"/>
        <xsl:sequence
            select="some $t in $tokenized-input satisfies $t = replace($token, '^\s+|\s+$', '')"/>
    </xsl:function>

    <xsl:param name="classes-to-merge" as="xs:string*" select="'USous-article', 'UCitation'"/>

    <xsl:template match="p[mf:contains-token(@class, 'Normal') and span[some $class in $classes-to-merge satisfies mf:contains-token(@class, $class)]]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="concat(node-name(.), '|', some $class in $classes-to-merge satisfies mf:contains-token(@class, $class), '|', @class)">
                <xsl:variable name="grouping-keys" select="tokenize(current-grouping-key(), '\|')"/>
                <xsl:choose>
                    <xsl:when test="$grouping-keys[1] and $grouping-keys[2] = 'true' and $grouping-keys[3]">
                        <xsl:copy>
                            <xsl:apply-templates select="@*, current-group()/node()"/>
                        </xsl:copy>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>    

</xsl:transform>

http://xsltransform.hikmatu.com/jyyiVhq

【讨论】:

  • 谢谢,这正是我想要做的,当我尝试使用 Saxon 时它正在工作,但不幸的是我无法在我的应用程序中使用 XSLT 3。
  • @R.BR,我尝试使用组合键将 XSLT 3 方法转录为使用连接键的 XSLT 2。查看编辑。
  • 感谢 Martin 的宝贵时间和帮助。也很抱歉,我通常会尝试自己做所有事情,但如果有一周的使用 XSL 的经验,我会很头疼:)
猜你喜欢
  • 2016-02-22
  • 2011-03-08
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 2022-11-10
相关资源
最近更新 更多