xslt:重新设置上下文节点中的属性值和具有相同@值的另一个节点

时间:2016-06-24 15:49:42

标签: xml xslt

鉴于此xml

<?xml version="1.0"?>
<root>
    <lev1>
        <source id="1"/>
        <target id="1"/>
    </lev1>
    <lev1>
        <source id="2"/>
        <sometag/>
        <lev2>
            <sometag/>
            <target id="2"/>
            <target id="4"/>
        </lev2>
        <source id="4"/>
        <sometag/>
        <source id="5"/>
        <lev2>
            <target id="6"/>
        </lev2>
    </lev1>
</root>

我想重新编号所有source/@id值,并使用更新后的值更新任何匹配的target/@id。我希望所有节点都保留其原始位置,并且我想生成一个注释,其中找不到匹配的target/@id

这个xslt是我的出发点:

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

<xsl:key name="kTarget" match="target" use="@id"/>


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


<xsl:template match="source">
<xsl:variable name="newId">
    <xsl:number from="/" level="any"/>
</xsl:variable>
    <newsource>
    <xsl:attribute name="id"><xsl:value-of select="$newId"/></xsl:attribute>
    </newsource>
    <xsl:call-template name="renumTarget">
        <xsl:with-param name="newId"><xsl:value-of select="$newId"/></xsl:with-param>
    </xsl:call-template>
</xsl:template>

<xsl:template match="target"/>

<xsl:template name="renumTarget">
<xsl:param name="newId"/>
    <xsl:comment>new id : <xsl:value-of select="$newId"/> old id : <xsl:value-of select="@id"/></xsl:comment>
    <xsl:element name="newtarget">
        <xsl:attribute name="id"><xsl:value-of select="$newId"/></xsl:attribute>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>




</xsl:stylesheet>

我可以选择旧值和新值......但无法放置新节点。这也不能识别不存在匹配的@id的区域。

有没有办法在xslt中创建某种具有oldVal-&gt; newVal函数的地图?

谢谢!

1 个答案:

答案 0 :(得分:1)

我不确定您是否要分别为h1生成source的评论而没有相应的newsourcetarget而没有target,以下内容生成:

source

当应用于输入样本时,我得到输出

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

    <xsl:key name="kTarget" match="target" use="@id"/>
    <xsl:key name="kSource" match="source" use="@id"/>

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

    <xsl:template match="source" mode="number">
        <xsl:number level="any"/>
    </xsl:template>

    <xsl:template match="source">
        <xsl:variable name="newId">
            <xsl:apply-templates select="." mode="number"/>
        </xsl:variable>
        <newsource id="{$newId}"/>
        <xsl:if test="not(key('kTarget', @id))">
            <xsl:comment>
                    <xsl:value-of select="concat('No target for old id ', @id, ' replaced by ', $newId)"/>
                </xsl:comment>
        </xsl:if>
    </xsl:template>

    <xsl:template match="target[key('kSource', @id)]">
        <xsl:variable name="changed-id">
            <xsl:apply-templates select="key('kSource', @id)" mode="number"/>
        </xsl:variable>
        <target id="{$changed-id}"/>
    </xsl:template>

    <xsl:template match="target[not(key('kSource', @id))]">
        <xsl:call-template name="identity"/>
        <xsl:comment>
            <xsl:value-of select="concat('No source for target with id ', @id)"/>
        </xsl:comment>
    </xsl:template>

</xsl:stylesheet>