XSLT 按优先级在相同的节点之间进行选择



我一直在努力根据优先级从相同节点数组中选择正确的节点。

这是 XML:

<?xml version="1.0" encoding="UTF-8"?>
<LandXML>
<CgPoints>
<CgPoint name="name1" oID="id1"></CgPoint>
<CgPoint name="name2" oID="id2"></CgPoint>
<CgPoint name="name3" oID="id1"></CgPoint>
<CgPoint name="name4" oID="id1"></CgPoint>
<CgPoint name="name5" oID="id2"></CgPoint>
<CgPoint name="name6" oID="id3"></CgPoint>
</CgPoints>
<Points>
<Point uniqueID="name1" class="medium" text="text1"></Point>
<Point uniqueID="name2" class="medium" text="text2"></Point>
<Point uniqueID="name3" class="high" text="text3"></Point>
<Point uniqueID="name4" class="low" text="text4"></Point>
<Point uniqueID="name5" class="low" text="text5"></Point>
<Point uniqueID="name6" class="medium" text="text6"></Point>
</Points>
</LandXML>

我想做的是遍历CgPoints元素并从节点获取所有oID名称,当存在相同的oID名称时,仅选择元素中class属性最高的Points。之后,我想将text属性添加到拉取的oID名称中。

输出如下所示:

id1,text3, <!-- this is the node with `name` attribute value `name3` -->
id2,text2,
id3,text6, <!-- this is the node with `name` attribute value `name2` -->

这是我到目前为止想出的 xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
<xsl:output method="text" indent="no" encoding="utf-8"/> 
<xsl:variable name="fileExt" select="'txt'"/>
<!-- Comma separator -->
<xsl:variable name="separator" select="','"/>
<xsl:key name="keyHPoint" match="/LandXML/Points/Point" use="@uniqueID"/>
<xsl:template match="/">
<xsl:apply-templates select="/LandXML/CgPoints/CgPoint">
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/LandXML/CgPoints/CgPoint">
<xsl:variable name="name" select="./@name"/>
<xsl:variable name="id" select="./@oID"/>
<xsl:variable name="allpoints" select="/LandXML/CgPoints/CgPoint[@oID = $id]"/>
<xsl:variable name="Point1" select="key('keyHPoint', $allpoints/@oID)"/>
<xsl:choose>
<xsl:when test="count($allpoints) = 1">
<xsl:value-of select="concat($id, $separator)"/>
<xsl:apply-templates select="/LandXML/Points/Point[@uniqueID = $name]"/>
<xsl:call-template name="newline">
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$Point1[@class = 'high']">
<xsl:value-of select="concat($id, $separator)"/>
<xsl:apply-templates select="/LandXML/Points/Point[@uniqueID = $name]"/>
<xsl:call-template name="newline">
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$Point1[@class = 'medium']">
<xsl:value-of select="concat($id, $separator)"/>
<xsl:apply-templates select="/LandXML/Points/Point[@uniqueID = $numurs]"/>
<xsl:call-template name="newline">
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$Point1[@class = 'low']">
<xsl:value-of select="concat($id, $separator)"/>
<xsl:apply-templates select="/LandXML/Points/h:Point[@uniqueID = $name]"/>
<xsl:call-template name="newline">
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Text template -->
<xsl:template match="/LandXML/Points/Point">
<xsl:value-of select="concat(./@text, $separator)"/>
</xsl:template>
<!-- New line -->
<xsl:template name="newline">
<xsl:text>&#xa;</xsl:text>
</xsl:template>
</xsl:stylesheet>

使用此 xslt 我得到了所有节点的输出,不应用按优先级选择。 提前感谢任何帮助!

使用 XSLT 2 或 3 可以按oID属性分组,按引用的类对每个组进行排序(例如,通过在可能的值序列中获取index-of(,然后按排序顺序输出第一个组 (https://xsltfiddle.liberty-development.net/nc4NzQj/1(:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="class-order" as="xs:string*" select="'high', 'medium', 'low'"/>
<xsl:output method="text"/>
<xsl:key name="pref" match="Point" use="@uniqueID"/>
<xsl:template match="/">
<xsl:for-each-group select="LandXML/CgPoints/CgPoint" group-by="@oID">
<xsl:for-each select="current-group()">
<xsl:sort select="index-of($class-order, key('pref', @name)/@class)"/>
<xsl:if test="position() eq 1">
<xsl:value-of select="current-grouping-key(), key('pref', @name)/@text" separator=","/>
<xsl:text>&#10;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>

使用 XSLT 1,您可以以某种方式使用相同的算法,只有分组必须使用键和 Muenchian 分组以及排序,例如通过获取剩余类值 (https://xsltfiddle.liberty-development.net/nc4NzQj/2( 串联的字符串长度:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:param name="class-order" select="'high|medium|low'"/>
<xsl:output method="text"/>
<xsl:key name="point-group" match="CgPoint" use="@oID"/>
<xsl:key name="pref" match="Point" use="@uniqueID"/>
<xsl:template match="/">
<xsl:for-each select="LandXML/CgPoints/CgPoint[generate-id() = generate-id(key('point-group', @oID)[1])]">
<xsl:for-each select="key('point-group', @oID)">
<xsl:sort select="string-length(substring-after($class-order, key('pref', @name)/@class))" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="concat(@oID, ',', key('pref', @name)/@text, '&#10;')"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

最新更新