给出以下XML:
<?xml version="1.0" encoding="utf-8"?>
<BMECAT version="1.2">
<T_NEW_CATALOG>
<CATALOG_GROUP_SYSTEM>
<CATALOG_STRUCTURE type="root">
<GROUP_ID>1</GROUP_ID>
<PARENT_ID>0</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="node">
<GROUP_ID>2</GROUP_ID>
<PARENT_ID>1</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="node">
<GROUP_ID>3</GROUP_ID>
<PARENT_ID>1</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="leaf">
<GROUP_ID>4</GROUP_ID>
<PARENT_ID>2</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="leaf">
<GROUP_ID>5</GROUP_ID>
<PARENT_ID>3</PARENT_ID>
</CATALOG_STRUCTURE>
</CATALOG_GROUP_SYSTEM>
<ARTICLE_TO_CATALOGGROUP_MAP>
<ART_ID>ART1</ART_ID>
<CATALOG_GROUP_ID>5</CATALOG_GROUP_ID>
</ARTICLE_TO_CATALOGGROUP_MAP>
</T_NEW_CATALOG>
</BMECAT>
我需要将属性inUse=true
设置为CATALOG_STRUCTURE
s(以及它们在PARENT_ID
元素中引用的元素),这些属性在任何ARTICLE_TO_CATALOGGROUP_MAP/CATALOG_GROUP_ID
元素中引用。
我无法完全理解如何根据文档另一部分中的内容操作部分文档,特别是如果该部分基本上是一棵树但显示为扁平化。
首先我创建了这个,但却一直在编写markGroup
模板......
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xslt="http://xml.apache.org/xslt" exclude-result-prefixes="#all">
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template name="isUsed">
<xsl:param name="groupId" />
<xsl:if test="//CATALOG_GROUP_ID/text() = $groupId">true</xsl:if>
</xsl:template>
<xsl:template match="CATALOG_STRUCTURE">
<xsl:variable name="groupId" select="GROUP_ID/text()"/>
<xsl:variable name="isUsedDirectly">
<xsl:call-template name="isUsed">
<xsl:with-param name="groupId" select="$groupId"/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="CATALOG_STRUCTURE">
<xsl:if test="$isUsedDirectly = 'true'">
<xsl:attribute name="inUse">true</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
但是这只会选择“直接”组,并且不会将父项标记为应该使用它。
此示例的所需输出为:
<?xml version="1.0" encoding="utf-8"?>
<BMECAT version="1.2">
<T_NEW_CATALOG>
<CATALOG_GROUP_SYSTEM>
<CATALOG_STRUCTURE type="root" inUse="true">
<GROUP_ID>1</GROUP_ID>
<PARENT_ID>0</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="node">
<GROUP_ID>2</GROUP_ID>
<PARENT_ID>1</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="node" inUse="true">
<GROUP_ID>3</GROUP_ID>
<PARENT_ID>1</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="leaf">
<GROUP_ID>4</GROUP_ID>
<PARENT_ID>2</PARENT_ID>
</CATALOG_STRUCTURE>
<CATALOG_STRUCTURE type="leaf" inUse="true">
<GROUP_ID>5</GROUP_ID>
<PARENT_ID>3</PARENT_ID>
</CATALOG_STRUCTURE>
</CATALOG_GROUP_SYSTEM>
<ARTICLE_TO_CATALOGGROUP_MAP>
<ART_ID>ART1</ART_ID>
<CATALOG_GROUP_ID>5</CATALOG_GROUP_ID>
</ARTICLE_TO_CATALOGGROUP_MAP>
</T_NEW_CATALOG>
</BMECAT>
答案 0 :(得分:1)
我会定义一个键和一个递归函数来遍历引用:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf"
version="2.0">
<xsl:key name="ref" match="CATALOG_STRUCTURE" use="GROUP_ID"/>
<xsl:function name="mf:get-refs" as="element(CATALOG_STRUCTURE)*">
<xsl:param name="ids" as="xs:string*"/>
<xsl:variable name="refs" as="element(CATALOG_STRUCTURE)*" select="key('ref', $ids, $catalog)"/>
<xsl:sequence select="$refs, if (exists($refs)) then mf:get-refs($refs/PARENT_ID) else ()"/>
</xsl:function>
<xsl:variable name="catalog" select="/BMECAT/T_NEW_CATALOG/CATALOG_GROUP_SYSTEM"/>
<xsl:variable name="referenced" as="element(CATALOG_STRUCTURE)*" select="mf:get-refs(//ARTICLE_TO_CATALOGGROUP_MAP/CATALOG_GROUP_ID)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="CATALOG_STRUCTURE[some $ref in $referenced satisfies $ref is current()]">
<xsl:copy>
<xsl:attribute name="InUse" select="'true'"/>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
假设XSLT 2.0(或更高版本)处理器如Saxon 9或AltovaXML或XmlPrime或Exselt。
关于它是如何工作的,密钥允许我们通过CATALOG_STRUCTURE
引用GROUP_ID
元素,然后递归函数允许我们计算所有递归引用元素的序列。为了全部识别它们,变量referenced
全部选择它们,现在我们只需要为那些根据需要添加属性的元素设置模板,以实现模式CATALOG_STRUCTURE[some $ref in $referenced satisfies $ref is current()]
检查匹配的节点是其中一个$referenced
元素。
如果您可以访问像Saxon 9.6或9.7的商业版本这样的XSLT 3.0处理器,您甚至可以编写一个只采用变量referenced
的模式:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf"
version="3.0">
<xsl:key name="ref" match="CATALOG_STRUCTURE" use="GROUP_ID"/>
<xsl:function name="mf:get-refs" as="element(CATALOG_STRUCTURE)*">
<xsl:param name="ids" as="xs:string*"/>
<xsl:variable name="refs" as="element(CATALOG_STRUCTURE)*" select="key('ref', $ids, $catalog)"/>
<xsl:sequence select="$refs, if (exists($refs)) then mf:get-refs($refs/PARENT_ID) else ()"/>
</xsl:function>
<xsl:variable name="catalog" select="/BMECAT/T_NEW_CATALOG/CATALOG_GROUP_SYSTEM"/>
<xsl:variable name="referenced" as="element(CATALOG_STRUCTURE)*" select="mf:get-refs(//ARTICLE_TO_CATALOGGROUP_MAP/CATALOG_GROUP_ID)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="$referenced">
<xsl:copy>
<xsl:attribute name="InUse" select="'true'"/>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>