Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xslt XSL-如何匹配连续的逗号分隔标记_Xslt_Xpath - Fatal编程技术网

Xslt XSL-如何匹配连续的逗号分隔标记

Xslt XSL-如何匹配连续的逗号分隔标记,xslt,xpath,Xslt,Xpath,我试图匹配一系列逗号分隔的xml标记,然后对整个节点组和文本应用xslt转换。例如,给定以下部分XML: <p>Some text here <xref id="1">1</xref>, <xref id="2">2</xref>, <xref id="3">3</xref>. </p> 这里有一些文本 1. 2. 3. 最后,我想说: <p>Some tex

我试图匹配一系列逗号分隔的xml标记,然后对整个节点组和文本应用xslt转换。例如,给定以下部分XML:

<p>Some text here
    <xref id="1">1</xref>,
    <xref id="2">2</xref>,
    <xref id="3">3</xref>.
</p>
这里有一些文本
1.
2.
3.

最后,我想说:

<p>Some text here <sup>1,2,3</sup>.</p>
这里有一些文本1,2,3

在这一点上,一个更混乱的替代方案也是可以接受的:

<p>Some text here <sup>1</sup><sup>,</sup><sup>2</sup><sup>,</sup><sup>3</sup>.</p>
这里有一些文本1,2,3

我有从单个外部参照到sup的转换:

<xsl:template match="xref"">
    <sup><xsl:apply-templates/></sup>
</xsl:template>

第二种选择可以通过

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

<xsl:template match="p/text()[normalize-space() = ',' and preceding-sibling::node()[1][self::xref]]">
  <sup>,</sup>
</xsl:template>

<xsl:template match="xref">
  <sup>
    <xsl:apply-templates/>
  </sup>
</xsl:template>

</xsl:stylesheet>

,

如果您可以使用XSLT 2.0(例如,与Saxon 9或AltovaXML或XQSharp一起使用),那么下面是一个XSLT 2.0解决方案,它应该会生成您要求的第一个输出:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

<xsl:template match="p">
  <xsl:for-each-group select="node()" group-adjacent="self::xref or self::text()[normalize-space() = ',']">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <sup>
          <xsl:value-of select="current-group()/normalize-space()" separator=""/>
        </sup>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

有趣的问题+一,

以下是XSLT 2.0解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   exclude-result-prefixes="xs"
   version="2.0">
   <xsl:variable name="comma-regex">^\s*,\s*$</xsl:variable>

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

   <!-- Don't directly process xrefs that are second or later in a comma-separated series.
      Note that this template has a higher default priority than the following one,
      because of the predicate. -->
   <xsl:template match="xref[preceding-sibling::node()[1]/
      self::text()[matches(., $comma-regex)]/
      preceding-sibling::*[1]/self::xref]" />

   <!-- Don't directly process comma text nodes that are in the middle of a series. -->
   <xsl:template match="text()[matches(., $comma-regex) and
      preceding-sibling::*[1]/self::xref and following-sibling::*[1]/self::xref]" />

   <!-- for xrefs that first (or solitary) in a comma-separated series: -->
   <xsl:template match="xref">
      <sup>
         <xsl:call-template name="process-xref-series">
            <xsl:with-param name="next" select="." />
         </xsl:call-template>
      </sup>
   </xsl:template>

   <xsl:template name="process-xref-series">
      <xsl:param name="next"/>
      <xsl:if test="$next">
         <xsl:value-of select="$next"/>
         <xsl:variable name="followingXref"
            select="$next/following-sibling::node()[1]/
                     self::text()[matches(., $comma-regex)]/
                     following-sibling::*[1]/self::xref"/>
         <xsl:if test="$followingXref">
            <xsl:text>,</xsl:text>
            <xsl:call-template name="process-xref-series">
               <xsl:with-param name="next" select="$followingXref"/>
            </xsl:call-template>
         </xsl:if>         
      </xsl:if>

   </xsl:template>
</xsl:stylesheet>

^\s*,\s*$
,
(如果我们可以对输入进行一些假设,这可以简化。)

根据您提供的示例输入运行,结果为:

<p>Some text here
   <sup>1,2,3</sup>.
</p>
这里有一些文本
1,2,3.


更新:感谢@flyn1179提醒我解决方案没有产生想要的输出,我对其进行了轻微修改现在生成所需的“良好”格式

此XSLT 1.0转换

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes"/>

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

     <xsl:template match=
     "xref[not(preceding-sibling::node()[1]
                  [self::text() and starts-with(.,',')]
               )
          ]">

      <xsl:variable name="vBreakText" select=
      "following-sibling::text()[not(starts-with(.,','))][1]"/>

      <xsl:variable name="vPrecedingTheBreak" select=
       "$vBreakText/preceding-sibling::node()"/>

      <xsl:variable name="vFollowing" select=
      ".|following-sibling::node()"/>

      <xsl:variable name="vGroup" select=
      "$vFollowing[count(.|$vPrecedingTheBreak)
                  =
                   count($vPrecedingTheBreak)
                  ]
      "/>

      <sup>
       <xsl:apply-templates select="$vGroup" mode="group"/>
      </sup>
      <xsl:apply-templates select="$vBreakText"/>
     </xsl:template>

     <xsl:template match="text()" mode="group">
       <xsl:value-of select="normalize-space()"/>
     </xsl:template>
</xsl:stylesheet>
<p>Some text here        
    <sup>1,2,3</sup>.    
    <ttt/>
    <sup>4,5,6</sup>.    
    <zzz/>
</p>

应用于以下XML文档时(基于提供的文档,但变得更复杂和有趣):

这里有一些文本
1.
2.
3.
4.
5.
6.

准确地生成所需的正确结果

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes"/>

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

     <xsl:template match=
     "xref[not(preceding-sibling::node()[1]
                  [self::text() and starts-with(.,',')]
               )
          ]">

      <xsl:variable name="vBreakText" select=
      "following-sibling::text()[not(starts-with(.,','))][1]"/>

      <xsl:variable name="vPrecedingTheBreak" select=
       "$vBreakText/preceding-sibling::node()"/>

      <xsl:variable name="vFollowing" select=
      ".|following-sibling::node()"/>

      <xsl:variable name="vGroup" select=
      "$vFollowing[count(.|$vPrecedingTheBreak)
                  =
                   count($vPrecedingTheBreak)
                  ]
      "/>

      <sup>
       <xsl:apply-templates select="$vGroup" mode="group"/>
      </sup>
      <xsl:apply-templates select="$vBreakText"/>
     </xsl:template>

     <xsl:template match="text()" mode="group">
       <xsl:value-of select="normalize-space()"/>
     </xsl:template>
</xsl:stylesheet>
<p>Some text here        
    <sup>1,2,3</sup>.    
    <ttt/>
    <sup>4,5,6</sup>.    
    <zzz/>
</p>
这里有一些文本
1,2,3.    
4,5,6.    

说明

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes"/>

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

     <xsl:template match=
     "xref[not(preceding-sibling::node()[1]
                  [self::text() and starts-with(.,',')]
               )
          ]">

      <xsl:variable name="vBreakText" select=
      "following-sibling::text()[not(starts-with(.,','))][1]"/>

      <xsl:variable name="vPrecedingTheBreak" select=
       "$vBreakText/preceding-sibling::node()"/>

      <xsl:variable name="vFollowing" select=
      ".|following-sibling::node()"/>

      <xsl:variable name="vGroup" select=
      "$vFollowing[count(.|$vPrecedingTheBreak)
                  =
                   count($vPrecedingTheBreak)
                  ]
      "/>

      <sup>
       <xsl:apply-templates select="$vGroup" mode="group"/>
      </sup>
      <xsl:apply-templates select="$vBreakText"/>
     </xsl:template>

     <xsl:template match="text()" mode="group">
       <xsl:value-of select="normalize-space()"/>
     </xsl:template>
</xsl:stylesheet>
<p>Some text here        
    <sup>1,2,3</sup>.    
    <ttt/>
    <sup>4,5,6</sup>.    
    <zzz/>
</p>
  • 我们使用“细粒度”标识规则,该规则按文档顺序逐节点处理文档,并“按原样”复制匹配的节点

  • 我们使用一个模板覆盖标识规则,该模板匹配任何
    xref
    元素,该元素是
    xref
    元素组中的第一个元素,每个元素(但最后一个)后面都有一个以“,”字符开头的直接文本节点同级。这里我们找到了第一个违反规则的文本节点同级(它的起始字符不是“,”

  • 然后,我们使用Kayessian(在@Michael Kay之后)公式计算两个节点集的交点,找到组中的所有节点。这个公式是:
    $ns1[count(.|$ns2)=count($ns2)]

  • 然后,我们以名为“组”的模式处理组中的所有节点

  • 最后,我们将模板(在匿名模式下)应用于中断文本节点(即组后面的第一个节点),以便处理链继续


  • 对于你的“混乱的选择”,有一个几乎微不足道的解决方案:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
    <xsl:template match="xref">
      <sup>
        <xsl:apply-templates />
      </sup>
    </xsl:template>
    
    <xsl:template match="text()[normalize-space(.)=',']">
      <sup>,</sup>
    </xsl:template>
    
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*| node()" />
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    有趣…你可以使用布尔值作为分组键?!我认为,一旦你将注意力集中在它周围,这是有意义的…虽然非常优雅,但这种方法的缺点是,如果只有逗号的文本节点出现在
    xref
    旁边,而不是出现在两个
    xref
    之间,它仍然会被视为
    的一部分<代码>一些文本1和更多。

    :逗号将作为
    的一部分出现,但不应该出现。顺便说一句,这需要XSLT 2.0的唯一原因是正则表达式匹配函数。如果将
    匹配(,$comma regex)
    更改为
    规范化空格(.)=','
    ,正如在@Martin的回答中一样,您可以使用XSLT 1.0。注意-我需要添加priority=“1”进入xsl:template,该模板与第一次外部参照之后发生的外部参照相匹配。我收到了不明确的匹配警告,并且其他外部参照正在通过过程外部参照系列。这很好-谢谢!同样在同一模板中,将
    前面的同级::node()/
    更改为
    前面的同级::node()[1]/
    允许在单个
    p
    @Pocket中使用多个外部参照跨距:感谢对前面的兄弟姐妹::node()[1]-这是我应该首先编写的内容。现在编辑我的答案。实际上我必须在另外两个地方添加
    [1]
    (在匹配
    text()
    的模板中)还有。@Pocket:哪个XSLT处理器给了您不明确的匹配警告?您提到的模板应该具有默认优先级0.5,因为匹配有一个谓词。具有
    match=“xref”
    的模板应该具有默认优先级0(请参阅)。好问题,+1。有关完整、不太长、也不太复杂的XSLT 1.0解决方案,请参阅我的答案。还添加了详细说明。在@Flynn1179提醒我的解决方案生成的输出不完全是所需的输出后,我已更新了解决方案。现在,此解决方案生成了所需的“良好格式”!给出的结果不是想要的结果;逗号应该包含在
    sup
    标记中。我建议添加此模板:
    @Flynn1179:谢谢--我没有注意到这一点。现在我更新了解决方案,以生成“良好”格式。:)有趣的标识规则+1Hm,当输入
    一些文本1、2和更多时。

    ,它输出
    一些文本1、2和更多。

    。“和更多”不应该在
    里面,是吗?另外,输入
    一些文本1,以及更多。

    给出了
    一些文本:1消失了。@LarsH:我没有时间对此进行广泛的测试,但是