我有以下输入XML,需要使用xslt
进行转换输入Xml:
<element>
<childelement xml:type="base" id="645">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement >
<childelement xml:type="level1" id="646">
<seg1>a</seg1>
<seg2>B</seg2>
<seg3>1</seg3>
</childelement>
<childelement xml:type="level2" id="656">
<seg1>a</seg1>
<seg2>C</seg2>
<seg3>0</seg3>
</childelement>
</element>
<element>
<childelement xml:type="base" id="647">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement>
<childelement xml:type="level1" id="648">
<seg1>a</seg1>
<seg2>B</seg2>
<seg3>0</seg3>
</childelement>
<childelement xml:type="level2" id="649">
<seg1>a</seg1>
<seg2>D</seg2>
<seg3>0</seg3>
</childelement>
</element>
预期产出:
<element>
<childelement xml:type="base" id="645">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement >
<childelement xml:type="level1" id="646">
<seg1>a</seg1>
<seg2>B</seg2>
<seg3>1</seg3>
</childelement>
<childelement xml:type="level2" id="656">
<seg1>a</seg1>
<seg2>C</seg2>
<seg3>0</seg3>
</childelement>
</element>
<element>
<childelement xml:type="base" id="647">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement>
<childelement xml:type="level2" id="649">
<seg1>a</seg1>
<seg2>D</seg2>
<seg3>0</seg3>
</childelement>
</element>
所以我想要做的是确定所有具有相同属性但基数的childelements(即此处level1和level2可能更高的级别)和seg1和seg2的相同innertext,只保留第一个具有最高的childelements seg3(在这种情况下是id = 646的那个并过滤掉id = 648的那个)。
xml / xlst是否可以进行这样的处理(根据属性和innertext匹配重复项)?
感谢您阅读
答案 0 :(得分:2)
这是一个XSLT 2.0样式表:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="dist" match="childelement[not(@xml:type = 'base')]"
use="concat(@xml:type, '|', seg1, '|', seg2)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="childelement[not(@xml:type = 'base')][seg3 < max(key('dist', concat(@xml:type, '|', seg1, '|', seg2))/seg3)]"/>
</xsl:stylesheet>
将Saxon 9应用于输入样本(添加了root
元素)时,输出为
<root>
<element>
<childelement xml:type="base" id="645">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement>
<childelement xml:type="level1" id="646">
<seg1>a</seg1>
<seg2>B</seg2>
<seg3>1</seg3>
</childelement>
<childelement xml:type="level2" id="656">
<seg1>a</seg1>
<seg2>C</seg2>
<seg3>0</seg3>
</childelement>
</element>
<element>
<childelement xml:type="base" id="647">
<seg1>a</seg1>
<seg2>A</seg2>
<seg3>0</seg3>
</childelement>
<childelement xml:type="level2" id="649">
<seg1>a</seg1>
<seg2>D</seg2>
<seg3>0</seg3>
</childelement>
</element>
</root>
如果您需要使用XSLT 1.0处理器,那么</ p>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="dist" match="childelement[not(@xml:type = 'base')]"
use="concat(@xml:type, '|', seg1, '|', seg2)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="childelement[not(@xml:type = 'base')]">
<xsl:variable name="this" select="."/>
<xsl:for-each select="key('dist', concat(@xml:type, '|', seg1, '|', seg2))">
<xsl:sort select="seg3" data-type="number" order="descending"/>
<xsl:if test="position() = 1 and generate-id() = generate-id($this)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
是我将XSLT 2.0方法转换为XSLT 1.0的版本。
答案 1 :(得分:-1)
XSLT 1.0也是如此:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="similar"
match="childelement[not(@xml:type = 'base')]"
use="concat(@xml:type, '|', seg1, '|', seg2)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="childelement[@xml:type!='base']">
<xsl:variable name="highestId">
<xsl:for-each select="key('similar', concat(@xml:type, '|', seg1, '|', seg2))">
<xsl:sort select="seg3" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="@id"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:if test="@id = $highestId">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>