简体   繁体   English

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

[英]Move attributes from one xml file to another via xslt

So I have an XML file with the following format: 因此,我有一个具有以下格式的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>
[...]

The problem is that the image attributes aren't always right, and they don't have a unique identifier. 问题在于图像属性并不总是正确的,并且它们没有唯一的标识符。 I have another file that has all the correct attributes. 我有另一个具有所有正确属性的文件。 I'm trying to write a transform that will remove the incorrect attributes, and then place the correct attributes from my other file. 我正在尝试编写一个转换,该转换将删除不正确的属性,然后从其他文件放置正确的属性。

Here's what I have so far: 这是我到目前为止的内容:

<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>

This successfully removes all of my incorrect attributes, but it doesn't place the correct ones. 这样可以成功删除我所有不正确的属性,但不会放置正确的属性。 It seems like my 'if' statement is never hitting, but I know that the paths are the same. 似乎我的'if'语句从未奏效,但我知道路径是相同的。 What did I do wrong? 我做错了什么?

my correct.xml looks like this (which is also what the output should look like): 我的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>
    [...] 

If the structure of the 2 XML docs match exactly, you can match the paths using positional predicates. 如果两个XML文档的结构完全匹配,则可以使用位置谓词匹配路径。 This will ensure that you're comparing unique paths. 这将确保您正在比较唯一路径。

Otherwise you'll have to match on id's or something. 否则,您必须匹配ID或其他内容。 If that's the case, let me know and I can update my answer to use the id (or whatever) attributes when generating the paths. 如果是这种情况,请告诉我,我可以在生成路径时更新答案以使用id (或任何其他属性)。

XML Input 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>

Correct XML (I named it so_good.xml.) 正确的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 (also works as 1.0) 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 Output 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>

To help show what's being compared, you can add this xsl:message to the "new-attrs" moded "image" template: 为了帮助显示正在比较的内容,可以将此xsl:message添加到“ new-attrs”模式的“ image”模板中:

<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>

You should see messages like: (sorry for the image) 您应该看到类似以下的消息:(对不起,该图片)

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM