通过xslt将属性从一个xml文件移动到另一个xml文件

时间:2014-05-23 16:33:53

标签: xml xslt

所以我有一个XML文件,格式如下:

[...]
<level1>
    <para id="1"/>
    <image type="photo" artist="Joe"/>
    <para id="2"/>
    <para id="3"/>
    <level2>
        <para id="4"/>
        <image type="pencil" artist="Bob"/>
        <para id="5"/>
    </level2>
    <para id="6"/>
    <image type="oil" artist="Joe"/>
</level1>
[...]

问题在于图像属性并不总是正确的,并且它们没有唯一的标识符。我有另一个具有所有正确属性的文件。我试图编写一个将删除不正确属性的转换,然后从我的其他文件中放入正确的属性。

这是我到目前为止所拥有的:

<xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- ============================================================= -->
    <xsl:variable name="target" select="document('correct.xml')//image"/>


    <xsl:template match="image">
        <xsl:variable name="vPath1">
            <xsl:for-each select="ancestor-or-self::*">
                <xsl:value-of select="concat('/',name())"/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:variable name="vPath2">
            <xsl:for-each select="$target[ancestor-or-self::*]">
                <xsl:value-of select="concat('/',name())"/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:copy>
            <xsl:if test="$vPath1=$vPath2">
                <xsl:copy-of select="$target/@*"/>
            </xsl:if>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

这成功删除了所有不正确的属性,但它没有放置正确的属性。看起来像我的&#39; if&#39;声明永远不会打,但我知道路径是一样的。我做错了什么?

我的correct.xml看起来像这样(输出应该是这样的):

[...]
<level1>
    <para id="1"/>
    <image type="pencil" artist="Joe"/>
    <para id="2"/>
    <para id="3"/>
    <level2>
        <para id="4"/>
        <image type="photo" artist="Steve"/>
        <para id="5"/>
    </level2>
    <para id="6"/>
    <image type="oil" artist="Bob"/>
</level1>
    [...] 

1 个答案:

答案 0 :(得分:1)

如果2个XML文档的结构完全匹配,则可以使用位置谓词匹配路径。这将确保您比较独特的路径。

否则你必须匹配id或其他东西。如果是这种情况,请告诉我,我可以在生成路径时更新我的​​答案以使用id(或其他)属性。

XML输入

<level1>
    <para id="1"/>
    <image type="photo" artist="Joe"/>
    <para id="2"/>
    <para id="3"/>
    <level2>
        <para id="4"/>
        <image type="pencil" artist="Bob"/>
        <para id="5"/>
    </level2>
    <para id="6"/>
    <image type="oil" artist="Joe"/>
</level1>

更正XML (我将其命名为so_good.xml。)

<level1>
    <para id="1"/>
    <image type="pencil" artist="Joe"/>
    <para id="2"/>
    <para id="3"/>
    <level2>
        <para id="4"/>
        <image type="photo" artist="Steve"/>
        <para id="5"/>
    </level2>
    <para id="6"/>
    <image type="oil" artist="Bob"/>
</level1>

XSLT 2.0 (也适用于1.0)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="good" select="document('so_good.xml')"/>

    <xsl:template name="getPath">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="concat('/',local-name())"/>
            <!--Predicate is only output when needed.-->
            <xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
                <xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

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

    <xsl:template match="image">
        <xsl:variable name="currPath">
            <xsl:call-template name="getPath"/>
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="$good//image" mode="new-attrs">
                <xsl:with-param name="currPath" select="$currPath"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>        
    </xsl:template>

    <xsl:template match="image" mode="new-attrs">
        <xsl:param name="currPath"/>
        <xsl:variable name="goodPath">
            <xsl:call-template name="getPath"/>
        </xsl:variable>
        <xsl:if test="$currPath=$goodPath">
            <xsl:copy-of select="@*"/>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

XML输出

<level1>
   <para id="1"/>
   <image type="pencil" artist="Joe"/>
   <para id="2"/>
   <para id="3"/>
   <level2>
      <para id="4"/>
      <image type="photo" artist="Steve"/>
      <para id="5"/>
   </level2>
   <para id="6"/>
   <image type="oil" artist="Bob"/>
</level1>

为了帮助显示所比较的内容,您可以将此xsl:message添加到“new-attrs”模式“图片”模板中:

<xsl:message>Comparing "<xsl:value-of select="$currPath"/>" (currPath) to "<xsl:value-of select="$goodPath"/>" (goodPath). Do they match? <xsl:value-of select="boolean($currPath=$goodPath)"/></xsl:message>

您应该看到以下消息:(对不起图像)

enter image description here