【问题标题】:how to compare xpath to current node如何将xpath与当前节点进行比较
【发布时间】:2020-07-24 01:12:09
【问题描述】:

我正在使用 saxon 将 xml 转换为 xsl-fo。每个文件都有一个伴随文件,其中包含已更改元素的 xpath。我需要将伴随文件中的 xpath 与当前节点进行比较。例如,如果当前正在处理的节点是 item8,那么根据伴随文件它应该得到一个更改栏:

xml文件

<body>
    <unlist bulltype="NDASH" code="00019292.0001001.007" layer="1" lid="N.00019292.0001001.014">
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.015">item1</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.018">item2</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.019">item3</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.020">item4</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.021">item5</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.022">item6</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.023">item7</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.024">item8</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.025">item9</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.026">item10</para>
        </item>
    </unlist>
</body>

配套文件

<rev-marks>
    <rev anchor="false" chg="R" origin="airbus"
      path="//*[@lid='N.00019292.0001001.014']/item[9]/para[1]"/>
    <rev anchor="false" chg="R" origin="airbus"
      path="//*[@lid='N.00019292.0001001.014']/item[8]/para[1]">
      <hl-ref ref="hl_1"/>
    </rev>
    <rev anchor="true" chg="R" origin="airbus" path="//*[@lid='N.00019292.0001001.014']"/>
  </rev-marks>

如果当前节点的路径与伴随文件中的 rev/@path 匹配,基本上我需要放置一个 fo 更改栏。任何帮助将不胜感激。

已编辑以显示我到目前为止所拥有的内容

<xsl:template match="para">
<!-- path of the current node -->
<xsl:variable name="curPath" select="saxon:path()"/> 
<!-- path of the companion file --> 
<xsl:variable name="mdata">../MU/<xsl:value-of select="ancestor::description/@code"/>_mdata.xml</xsl:variable>
        
<xsl:for-each select="document($mdata,.)//rev">
    <!-- value of //rev/@path in the companion file -->
    <xsl:variable name="revPath" select="@path"/>
                
    <xsl:if test="$revPath = $curPath">
        <fo:change-bar-begin change-bar-class="cbpara" change-bar-color="black" change-bar-style="solid" change-bar-offset="15pt"/>
    </xsl:if>
            
</xsl:for-each>
<fo:block>
    <xsl:apply-templates/>
</fo:block>
<!-- add fo:change-bar-end here -->
</xsl:template>

正是这个语句,我无法比较 2 个 xpath 表达式

希望这可以澄清

【问题讨论】:

  • 您可以编辑您的帖子以包含您迄今为止创建的任何 xsl(或它的相关部分)吗?您是否需要有关如何包含 partner.xml 文件的帮助? (使用 ),或读取值,或创建 xpath 以执行匹配?
  • @Bryn 此编辑是否有助于澄清?
  • 迈克尔凯的回答是正确的。您想采用他的第一种 (XSLT3) 还是第二种 (XSLT1) 方法?如果您使用的是 xslt3,则可以使用 &ltxsl:evaluate> (请参阅 Martin Honnen 的回答)

标签: xml compare xsl-fo saxon


【解决方案1】:

对此有两种通用方法。

一种是使用xsl:evaluate 来评估伴随文件中的XPath 表达式。确切的解决方案取决于需求的细节:例如,我不确定是否所有&lt;rev&gt; 元素都以相同的方式处理,或者@anchor@rev@origin 属性的意义是什么.

第二种方法是编写一个转换,将您的伴随文件转换为执行实际工作的 XSLT 样式表(通常,每个&lt;rev&gt; 元素都转换为带有匹配模式的xsl:template)。这听起来有点令人生畏,但它可能是更优雅的方法。

【讨论】:

    【解决方案2】:

    使用xsl:evaluate(在 Saxon 9.8 及更高版本的 PE 和 EE 版本、Saxon 10 所有版本和 Saxon-JS 2 中支持)的示例是:

    <?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"
        xmlns:mf="http://example.com/mf"
        exclude-result-prefixes="#all"
        version="3.0">
        
        <xsl:param name="rev-doc-uri" as="xs:string">evaluate-key-ref-marks.xml</xsl:param>
        
        <xsl:param name="rev-doc" select="doc($rev-doc-uri)"/>
        
        <xsl:function name="mf:select-node" as="node()*">
            <xsl:param name="path" as="xs:string"/>
            <xsl:param name="context-doc" as="node()"/>
            <xsl:evaluate context-item="$context-doc" xpath="$path"/>
        </xsl:function>
        
        <xsl:mode on-no-match="shallow-copy"/>
        
        <xsl:template match="*[some $rev in $rev-doc//rev[@path] satisfies (. is mf:select-node($rev/@path, /))]">
            <xsl:comment>marked</xsl:comment>
            <xsl:next-match/>
        </xsl:template>
        
    </xsl:stylesheet>
    

    Online sample using Saxon-JS 2 in the browser (second XML is inlined there for self-completeness of the example).

    【讨论】:

    • 如何处理像 //item/para 这样的模棱两可的 rev/@path?有这样的情况,所有项目/段落都应该被标记。在您的示例中,它仅标记了 item/para[8] 和 item/para[9]
    • @user3618078,我不确定我是否记得所有细节,但我想你想要例如xsl:template match="*[some $rev in $rev-doc//rev[@path] satisfies (. intersect mf:select-nodes($rev/@path, /))]" 我只是将现有函数重命名为mf:select-nodes
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多