简体   繁体   English

在父级之间移动xml节点并删除重复项-xslt 2.0

[英]Move xml nodes between parents and delete duplicates - xslt 2.0

I have an xml as follows and would like to 1) move values in the Data node to Header if the match the attribute name or 2) delete nodes under Data if the name attribute is the same as an existing node in the header using xsl tranform, if possible. 我有一个xml,如下所示,想1)如果属性名称匹配,则将“数据”节点中的值移至“标头”,或2)如果名称属性与使用xsl转换的标头中的现有节点相同,则删除“数据”下的节点, 如果可能的话。 Any help would be greatly appreciated. 任何帮助将不胜感激。

Initial xml: 初始xml:

<HEADER>
   <KEY name="child1" value="value1" />
   <KEY name="child2" value="value2" />
   <KEY name="child3" value="value3" />
   <KEY name="child4" value="value4" />
</HEADER>
<DATA>
   <KEY name="child1" value="value1.data" />
   <KEY name="child3" value="value3.data" />
   <KEY name="child5" value="value5" />
   <KEY name="child7" value="value7" />
</DATA>

If Child 5 is the node to move, the result is...After Transform: 如果子节点5是要移动的节点,则结果为...转换后:

<HEADER>
   <KEY name="child1" value="value1" />
   <KEY name="child2" value="value2" />
   <KEY name="child3" value="value3" />
   <KEY name="child4" value="value4" />
   <KEY name="child5" value="value5" />
</HEADER>
<DATA>
   <KEY name="child7" value="value7" />
</DATA>

current xsl: 当前的xsl:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output omit-xml-declaration="no" method="xml" indent="yes" />

    <!-- <xsl:variable name="ReplaceLiveDate" select="false()" /> -->
    <xsl:variable name="ReplaceLiveDate" select="true()" />

    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

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

    <!-- in HEADER: output ROLE sorted by @name -->
    <xsl:template match="HEADER">
        <xsl:copy>
            <xsl:apply-templates select="KEY">
                <xsl:sort select="translate(@name, $smallcase, $uppercase)" order="ascending" />
                <!-- <xsl:sort select="@name" /> -->
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <!-- in DATA: output KEY sorted by @name -->
    <xsl:template match="DATA">
        <xsl:copy>
            <xsl:apply-templates select="KEY">
                <xsl:sort select="translate(@name, $smallcase, $uppercase)" order="ascending" />
                <!-- <xsl:sort select="@name" /> -->
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template> 

I have the following to remove nodes, but unsure how to only do it if the node exist in the header section 我有以下删除节点的方法,但不确定仅在标头部分中存在该节点的情况下如何执行此操作

<!-- remove processing nodes -->
<xsl:template match="KEY[starts-with(@name, 'child1')]"/>

there are many ways to do that transformation, but in this case i think that the smart one is to use the xslt keys feature see here for a brief description 有很多方法可以进行这种转换,但是在这种情况下,我认为明智的选择是使用xslt 键功能,请参见此处的简要说明。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
    <xsl:output omit-xml-declaration="no" method="xml" indent="yes" />

    <!-- <xsl:variable name="ReplaceLiveDate" select="false()" /> -->
    <xsl:variable name="ReplaceLiveDate" select="true()" />

    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

    <!-- index all the KEY element of the HEADER -->
    <xsl:key name='head' match='HEADER/KEY' use='@name' />


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


    <xsl:template match='HEADER'>
        <xsl:copy>
            <!--  move the child5 'KEY element' under the header  -->
            <xsl:copy-of select="//DATA/KEY[@name = 'child5']"/>
            <!--  apply to childs   -->
            <xsl:apply-templates select="KEY">
                <xsl:sort select="translate(@name, $smallcase, $uppercase)" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <!-- delete key nodes duplicated in Header, that is elments not indexed by the 'head' key -->
    <xsl:template match="DATA/KEY[key('head',@name)]">
    </xsl:template>

    <!--  delete the node to be moved -->
    <xsl:template match="DATA/KEY[@name = 'child5']" />

</xsl:stylesheet>

For simplicity the stylesheet above won't sort the header keys in alphabethical order, if you really need it, then a perform-sort is necessary. 为简单起见,上面的样式表不会按字母顺序对标题键进行排序,如果确实需要,则必须进行执行排序

I tried to keep much as possible of your original stylesheet, but I didn't find out any other solution following that way. 我试图保留尽可能多的原始样式表,但是按照这种方式,我没有找到其他解决方案。

Below the template if you want key sorted by the @name attribute 如果要按@name属性对键进行排序,则在模板下方

<xsl:template match='HEADER'>

    <xsl:variable name='unsorted_keys'>
        <xsl:copy-of select="//DATA/KEY[@name = 'child5']"/>
        <!--  apply to childs   -->
        <xsl:apply-templates select="KEY">
        </xsl:apply-templates>          
    </xsl:variable>

    <xsl:copy>      
        <!--  make sure to copy HEADER attributes  -->
        <xsl:apply-templates select='@*'/>

        <!--  perform sort  -->
        <xsl:perform-sort select="$unsorted_keys/KEY">
            <xsl:sort select="translate(@name, $smallcase, $uppercase)" order="ascending" />
        </xsl:perform-sort>         
    </xsl:copy>
</xsl:template>

Hope this helps 希望这可以帮助

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

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