Я хочу объединить два файла A.xml и map.xml с элементами "Node" в соответствии со следующим правилом (узлы различаются @Name):
- Если элемент в map.xml имеет атрибут Src, элемент из карты следует скопировать в выходной файл
- Если элемент существует в A и map и НЕ имеет @Src, его следует скопировать из A
- Если элемент существует в A, но отсутствует на карте, его следует игнорировать (с предупреждением)
- Если элемент существует в карте, но не в A, должен быть сгенерирован (пустой) элемент
Пример:
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>
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>
Результат должен быть:
<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>
Мой 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>
Скрипт работает отлично. Он обрабатывает A.xml и ищет каждый элемент Node в map.xml. Поскольку узлы @Src и non-@ 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>
Итак, Child4_Sub2 генерируется дважды, что не имеет смысла, так как Child4_Sub2 в любом случае будет нуждаться в Child4 в качестве родителя! Но до сих пор я не нашел способа предотвратить печать этого элемента.
У вас есть какие-нибудь подсказки?
С уважением,
DIVB