检查*output*节点是否已存在

div*_*ivB 2 xml xslt

我想根据以下规则将两个文件A.xml和map.xml与"Node"元素合并(节点由@Name区分):

  1. 如果map.xml中的元素具有Src属性,则应将map中的元素复制到输出
  2. 如果元素存在于A和map中且没有@Src,则应从A复制
  3. 如果元素存在于A但不存在于map中,则应忽略该元素(带警告)
  4. 如果元素存在于map中但不存在于A中,则应生成(empty)元素

例:

map.xml:

<?xml version="1.0"?>

<Node Name="ParentNode">
    <Node Name="Child1" Src="Child1/"/>
    <Node Name="Child2" Src="Child2/"/>
    <Node Name="Child3" Src="Child3/"/>

    <Node Name="Child4">
        <Node Name="Child4_Sub1" />
        <Node Name="Child4_Sub2" Src="Child4_Sub2/"/>
    </Node>

    <Node Name="Child5" />
</Node>
Run Code Online (Sandbox Code Playgroud)

A.XML:

<Node Name="ParentNode">
    <Node Name="Child4">
        <Node Name="Child4">
            <Node Name="Child4_Sub1">
                <!-- Here are many other elements -->
            </Node>
        </Node>
    </Node> 
    <!-- Here are many other elements -->
    <Node Name="Child1">
        <!-- Here are many other elements -->
    </Node>
    <!-- Here are many other elements -->

    <Node Name="ChildFoo">
        <!-- Here are many other elements -->
    </Node>
</Node>
Run Code Online (Sandbox Code Playgroud)

结果应该是:

<Node Name="ParentNode">
    <Node Name="Child4">
        <Node Name="Child4">
            <Node Name="Child4_Sub1">
                <!-- Here are many other elements -->
            </Node>
            <Node Name="Child4_Sub2" />
        </Node>
    </Node> 
    <!-- Here are many other elements -->
    <Node Name="Child1" Src="Child1" />
    <!-- Here are many other elements -->

    <Node Name="Child2" Src="Child2" />
    <Node Name="Child3" Src="Child3" />
</Node>
Run Code Online (Sandbox Code Playgroud)

我的XSLT脚本是:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0">
    <xsl:param name="mapFile" required="yes"/>

    <xsl:variable name="MapDiagram" select="document($mapFile,/*)"/>
    <xsl:variable name="CurrentDocument" select="/" />

    <!-- handle Node elements in A.xml -->
    <xsl:template match="Node">
        <xsl:variable name="MyName" select="@Name"/>
        <xsl:choose>
            <xsl:when test="$MapDiagram//Node[@Name = $MyName]">
                <xsl:choose>
                    <xsl:when test="$MapDiagram//Node[@Name = $MyName]/@Src">
                        <xsl:copy-of select="$MapDiagram//Node[@Name = $MyName]"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <Node Name="{@Name}" Type="{@Type}">
                            <xsl:apply-templates/>
                            <xsl:apply-templates select="$MapDiagram//Node[@Name = $MyName]" mode="MapDiagram" />
                        </Node>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:message terminate="no">WARNING: Node "<xsl:value-of select="@Name"/>" not found in map file, ignoring</xsl:message>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- handle Node elements from map file -->
    <xsl:template match="Node" mode="MapDiagram">
        <xsl:variable name="MyName" select="@Name"/>
        <xsl:choose>
            <xsl:when test="not($CurrentDocument//Node[@Name = $MyName])">
                <xsl:copy-of select="."/>
            </xsl:when>
            <xsl:otherwise>
                    <xsl:apply-templates mode="MapDiagram" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- Copy all other elements in between -->
    <xsl:template match="*[name() != 'Node']">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

该脚本工作正常.它处理A.xml并在map.xml中查找每个Node元素.由于可以混合@Src和非@ Src节点,因此可以递归调用它.

但是,此脚本生成:

<Node Name="ParentNode">
    <Node Name="Child4">
        <Node Name="Child4">
            <Node Name="Child4_Sub1">
                <!-- Here are many other elements -->
            </Node>
            <Node Name="Child4_Sub2" />
        </Node>
    </Node> 
    <!-- Here are many other elements -->
    <Node Name="Child1" Src="Child1" />
    <!-- Here are many other elements -->

    <Node Name="Child2" Src="Child2" />
    <Node Name="Child3" Src="Child3" />
    <Node Name="Child4_Sub2" />
</Node>
Run Code Online (Sandbox Code Playgroud)

因此,Child4_Sub2生成两次是没有意义的,因为Child4_Sub2无论如何都需要Child4作为父级!但到目前为止,我发现没有办法阻止这个元素被打印出来.

你有什么提示吗?

此致,divB

Dim*_*hev 5

更改:

      <xsl:apply-templates mode="MapDiagram" select=
        "$MapDiagram//Node[@Name = $MyName]"/>
Run Code Online (Sandbox Code Playgroud)

至:

    <xsl:if test="not(@Name = ancestor::Node/@Name)">
      <xsl:apply-templates mode="MapDiagram" select=
        "$MapDiagram//Node[@Name = $MyName]"/>
    </xsl:if>
Run Code Online (Sandbox Code Playgroud)

这是一个完整的解决方案:

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

    <xsl:param name="mapFile"
        select="'file:///c:/temp/delete/map.xml'"/>

        <xsl:variable name="MapDiagram" select="document($mapFile,/*)"/>
        <xsl:variable name="CurrentDocument" select="/" />

        <!-- handle Node elements in A.xml -->
        <xsl:template match="Node">
            <xsl:variable name="MyName" select="@Name"/>
            <xsl:choose>
                <xsl:when test="$MapDiagram//Node[@Name = $MyName]">

                    <xsl:choose>
                        <xsl:when test="$MapDiagram//Node[@Name = $MyName]/@Src">
                            <xsl:copy-of select="$MapDiagram//Node[@Name = $MyName]"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <Node Name="{@Name}" Type="{@Type}">
                                <xsl:apply-templates/>

                                <xsl:if test="not(@Name = ancestor::Node/@Name)">
                                  <xsl:apply-templates mode="MapDiagram" select=
                                     "$MapDiagram//Node[@Name = $MyName]"
                                  />
                                </xsl:if>
                            </Node>
                        </xsl:otherwise>
                    </xsl:choose>

                </xsl:when>
                <xsl:otherwise>
                    <xsl:message terminate="no">WARNING: Node "<xsl:value-of select="@Name"/>" not found in map file, ignoring</xsl:message>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>

        <!-- handle Node elements from map file -->
        <xsl:template match="Node" mode="MapDiagram">
            <xsl:variable name="MyName" select="@Name"/>
            <xsl:choose>
                <xsl:when test="not($CurrentDocument//Node[@Name = $MyName])">
                    <xsl:copy-of select="."/>
                </xsl:when>
                <xsl:otherwise>
                        <xsl:apply-templates mode="MapDiagram" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>

        <!-- Copy all other elements in between -->
        <xsl:template match="*[name() != 'Node']">
            <xsl:copy-of select="."/>
        </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

将此转换应用于提供的XML文档时:

<Node Name="ParentNode">
    <Node Name="Child4">
        <Node Name="Child4">
            <Node Name="Child4_Sub1"/>
        </Node>
    </Node>

    <Node Name="Child1"/>

    <Node Name="ChildFoo"/>
</Node>
Run Code Online (Sandbox Code Playgroud)

提供的"map.xml"是at C:\temp\delete\map.xml:

<Node Name="ParentNode">
    <Node Name="Child1" Src="Child1/"/>
    <Node Name="Child2" Src="Child2/"/>
    <Node Name="Child3" Src="Child3/"/>
    <Node Name="Child4">
        <Node Name="Child4_Sub1" />
        <Node Name="Child4_Sub2" Src="Child4_Sub2/"/>
    </Node>
    <Node Name="Child5" />
</Node>
Run Code Online (Sandbox Code Playgroud)

产生了想要的结果(不包含不需要的重复):

<Node Name="ParentNode" Type="">
   <Node Name="Child4" Type="">
      <Node Name="Child4" Type="">
         <Node Name="Child4_Sub1" Type=""/>
      </Node>
      <Node Name="Child4_Sub2" Src="Child4_Sub2/"/>
   </Node>
   <Node Name="Child1" Src="Child1/"/>
   <Node Name="Child2" Src="Child2/"/>
   <Node Name="Child3" Src="Child3/"/>
   <Node Name="Child4_Sub2" Src="Child4_Sub2/"/>
   <Node Name="Child5"/>
</Node>
Run Code Online (Sandbox Code Playgroud)

一般说明:提供的代码非常复杂和混乱 - 可能还有其他逻辑问题.没有使用XSLT 2.0语言功能 - 这本质上是一个XSLT 1.0解决方案.以更好的形式重写代码是个好主意.