XSLT 2.0使用xsl copy / copy-of for-each,覆盖某些属性

时间:2015-05-27 14:59:32

标签: xml xslt xslt-2.0

我遇到麻烦复制节点并在for-each循环中覆盖元素。

代码:

        <xsl:for-each select="key('doc_checks', @id, $doc_checks_File)">
            <xsl:if test="@id = $curID">
                <xsl:copy-of select="."/>
            </xsl:if>
        </xsl:for-each>

复制所有内容,这很好,但我需要覆盖两个属性(或者更确切地说,它们不应该复制到结果文档中)。

传递给key函数的文档如下所示:

<doc id="1eb79a4952644db089fd7eb049bb5b58" fileNameInDB="d041397121636931.xml" version="1">
        <docref id="ec699e0817fb46a0817b0fa276a249f8" fileNameInDB="d041385554715361.xml" href="ec699e0817fb46a0817b0fa276a249f8.xml" version="1">
            <docref id="91f233476f4d1014b6dd926db0e91070" fileNameInDB="d041385557506665.xml" href="91f233476f4d1014b6dd926db0e91070.xml" navtitle="Model View Controller (MVC) Approach"version="1">
                <docref id="e1b625940c104b558e52f47afe5ddb4f" fileNameInDB="c511393250787627.xml" href="e1b625940c104b558e52f47afe5ddb4f.xml" version="1"/>
                </docref>
        </docref>
</doc>

我在输出中需要相同的结构,但没有fileNameInDB属性。

修改

<xsl:stylesheet>

<xsl:key name="doc_checks" match="doc" use="@id"/>
<xsl:param name="doc_checks_File" select="fn:doc(fn:iri-to-uri('doc_checks.xml'))"/>

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

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

<xsl:template match="doc">

<xsl:variable name="curID" select="@id"/>

<xsl:for-each select="key('doc_checks', @id, $doc_checks_File)">
    <xsl:if test="@id = $curID">
        <!-- copy structure from $doc_checks_File -->
    </xsl:if>
</xsl:for-each>


</xsl:templates>

</xsl:stylesheet>

INPUT:

<docs>
<doc id="1eb79a4952644db089fd7eb049bb5b58"/>
<doc id="2379a4952563db089fd7e2dz049bb648"/>
<!-- and so on -->
</docs>

引用文档doc_checks.xml(关键功能):

<doc_checks>
    <doc id="1eb79a4952644db089fd7eb049bb5b58" fileNameInDB="d041397121636931.xml" version="1">
            <docref id="ec699e0817fb46a0817b0fa276a249f8" fileNameInDB="d041385554715361.xml" href="ec699e0817fb46a0817b0fa276a249f8.xml" version="1">
                <docref id="91f233476f4d1014b6dd926db0e91070" fileNameInDB="d041385557506665.xml" href="91f233476f4d1014b6dd926db0e91070.xml" navtitle="Model View Controller (MVC) Approach"version="1">
                    <docref id="e1b625940c104b558e52f47afe5ddb4f" fileNameInDB="c511393250787627.xml" href="e1b625940c104b558e52f47afe5ddb4f.xml" version="1"/>
                    </docref>
            </docref>
    </doc>

<doc id="2379a4952563db089fd7e2dz049bb648">
<!-- a couple of docrefs, like above -->
</doc>

预期输出(<new>无关紧要)

<new>
<doc id="1eb79a4952644db089fd7eb049bb5b58">
<docref id="ec699e0817fb46a0817b0fa276a249f8" href="ec699e0817fb46a0817b0fa276a249f8.xml" version="1">
                <docref id="91f233476f4d1014b6dd926db0e91070" href="91f233476f4d1014b6dd926db0e91070.xml" navtitle="Model View Controller (MVC) Approach"version="1">
                    <docref id="e1b625940c104b558e52f47afe5ddb4f"  href="e1b625940c104b558e52f47afe5ddb4f.xml" version="1"/>
                    </docref>
            </docref>
</doc>

<doc id="2379a4952563db089fd7e2dz049bb648">
<!-- the respective docref elements from doc_checks.xml -->
</doc>
</new>

2 个答案:

答案 0 :(得分:1)

xsl:copy-of复制所选节点及其整个后代树,无法进行选择。尝试改为:

<xsl:apply-templates select="key('doc_checks', @id, $doc_checks_File)[@id = $curID]"/>

然后有这两个模板来处理调用:

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

<xsl:template match="@fileNameInDB"/>

警告:您没有发布可重现的示例,因此在您的方案中可能需要进行一些更改。

编辑:

鉴于您添加的代码,以下是完整样式表上下文中的建议方法:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="doc_checks" match="doc" use="@id"/>
<xsl:param name="doc_checks_File" select="document('doc_checks.xml')"/>

<xsl:template match="/docs">
    <new>
        <xsl:for-each select="doc">
            <xsl:apply-templates select="key('doc_checks', @id, $doc_checks_File)"/>
        </xsl:for-each>
    </new>
</xsl:template>

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

<xsl:template match="@fileNameInDB"/>

</xsl:stylesheet>

应用于您的输入示例(在纠正doc_checks.xml文档以确定格式良好之后!!),结果为:

<?xml version="1.0" encoding="UTF-8"?>
<new>
   <doc id="1eb79a4952644db089fd7eb049bb5b58" version="1">
      <docref id="ec699e0817fb46a0817b0fa276a249f8"
              href="ec699e0817fb46a0817b0fa276a249f8.xml"
              version="1">
         <docref id="91f233476f4d1014b6dd926db0e91070"
                 href="91f233476f4d1014b6dd926db0e91070.xml"
                 navtitle="Model View Controller (MVC) Approach"
                 version="1">
            <docref id="e1b625940c104b558e52f47afe5ddb4f"
                    href="e1b625940c104b558e52f47afe5ddb4f.xml"
                    version="1"/>
         </docref>
      </docref>
   </doc>
   <doc id="2379a4952563db089fd7e2dz049bb648"><!-- a couple of docrefs, like above --></doc>
</new>

备注:

  1. 您的前两个模板是多余的; 内置模板规则 已经这样做了;

  2. 您的测试<xsl:if test="@id = $curID">是多余的; 已经处理好了。

答案 1 :(得分:0)

这对我有用:

<xsl:template match="someElement">
    <xsl:for-each select="key('keyname', concat(@id, '+', @folder), $reuseFile)/child::*">
        <xsl:copy>
<!-- overwrite attribute -->
            <xsl:attribute name="rev" select="@ver"/>
<!-- exclude certain attributes -->
                <xsl:copy-of select="@*[fn:local-name() != 'somename']"/>
            <xsl:apply-templates select="node()"/> <!-- chooses the template below -->
        </xsl:copy>
    </xsl:for-each>
</xsl:template>

<xsl:template match="abc | def">
    <xsl:copy>
        <xsl:attribute name="rev" select="@ver"/>
        <xsl:copy-of select="@*[fn:local-name() != 'somename']"/>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>