Xml xslt将具有相同属性的相邻同级折叠为一个,同时连接它们的文本

Xml xslt将具有相同属性的相邻同级折叠为一个,同时连接它们的文本,xml,xslt,Xml,Xslt,背景:以下是MSWord表单的xslt修改的xml摘录。MSWord表单中的某些文本以某种方式被拆分为多个元素,需要重新组合为单个元素。下面是倒数第二个XML输入的实际片段 <Section coord="2.13" posn="2" of="13"> <Segment coord="1.25" rowno="1" of="25"> <Entry coord="1.1" colno="1" of="1" desgn="Table">QU

背景:以下是MSWord表单的xslt修改的xml摘录。MSWord表单中的某些文本以某种方式被拆分为多个元素,需要重新组合为单个元素。下面是倒数第二个XML输入的实际片段

<Section coord="2.13" posn="2" of="13">
    <Segment coord="1.25" rowno="1" of="25">
        <Entry coord="1.1" colno="1" of="1" desgn="Table">QUAL</Entry>
        <Entry coord="1.1" colno="1" of="1" desgn="Table">I</Entry>
        <Entry coord="1.1" colno="1" of="1" desgn="Table">FICATIONS</Entry>
    </Segment>
    <Segment coord="2.25" rowno="2" of="25">
        <Entry coord="1.1" colno="1" of="1" desgn="Table">ACADEMIC QUALIFICATIONS</Entry>
        <Entry coord="1.1" colno="1" of="1" desgn="Table"> (Most recent first)</Entry>
    </Segment>
    <Segment coord="3.25" rowno="3" of="25">
        <Entry coord="1.4" colno="1" of="4" desgn="Column">Degree/Diploma/Certificate</Entry>
        <Entry coord="2.4" colno="2" of="4" desgn="Column">Institution</Entry>
        <Entry coord="3.4" colno="3" of="4" desgn="Column">Date Conferred</Entry>
        <Entry coord="3.4" colno="3" of="4" desgn="Column">(mm/yyyy)</Entry>
        <Entry coord="4.4" colno="4" of="4" desgn="Column">SAQA Evaluated?</Entry>
        <Entry coord="4.4" colno="4" of="4" desgn="Column">(If not SA qualification)</Entry>
    </Segment>
    <Segment coord="4.25" rowno="4" of="25"/>
    <!-- remaining 21 Segments from Section deleted ... -->
</Section>

夸尔
我
影响
学历
(最近的第一次)
学位/文凭/证书
机构
授予日期
(年月日)
SAQA评估?
(如果不是SA资格)
注意:@coord属性是从同级“position().last()”构造的

所需的合并输出: 例如,在带有@coord 1.25的段中,需要将三个条目折叠为一个条目:

资格认证

它们的文本被连接成一个

同样,第1.26段有两个条目,它们应折叠为:

<Entry coord="1.1" colno="1" of="1" desgn="Table">ACADEMIC QUALIFICATIONS (Most recent first)</Entry>
学历(最近的第一名)
这同样适用于第3.25段中的最后两个,具有不同的合并条目:

<Entry coord="3.4" colno="3" of="4" desgn="Column">Date Conferred(mm/yyyy)</Entry>
授予日期(mm/yyyy)

SAQA评估?(如果不是SA资格)
我能够(按文档顺序)测试@coord的重复,例如: test=“@coord=following sibling::Entry/@coord”开始连接 或 test=“@coord!=前面的同级::Entry/@coord”停止连接 但我的困难在于在连接它们的文本时延迟xsl:copy。它在文档顺序上变得混乱(我的失败和未完成的尝试只进行了一次连接,而没有按需要进行多次连接):


以相反的文档顺序进行连接似乎更为自然,但只要仔细考虑,它仍然很混乱。解决这个问题的最佳方法是什么

根据我对答案2的评论,如何扩展答案以进行建议的额外父级处理()。具有父属性(frags=子::文本片段的数量,size=连接文本片段的总字符串长度)的修改输入需要填充,并在下面的xml输入中显示为空属性

<Section coord="2.13" posn="2" of="13">
<Segment coord="1.25" rowno="1" of="25" frags="" size="">
<Entry coord="1.1" colno="1" of="1" desgn="Table" size="4">QUAL</Entry>
<Entry coord="1.1" colno="1" of="1" desgn="Table" size="1">I</Entry>
<Entry coord="1.1" colno="1" of="1" desgn="Table" size="9">FICATIONS</Entry>
</Segment>
<Segment coord="2.25" rowno="2" of="25" frags="" size="">
<Entry coord="1.1" colno="1" of="1" desgn="Table" size="23">ACADEMIC QUALIFICATIONS</Entry>
<Entry coord="1.1" colno="1" of="1" desgn="Table" size="20"> (Most recent first)</Entry>
</Segment>
<Segment coord="3.25" rowno="3" of="25" frags="" size="">
<Entry coord="1.4" colno="1" of="4" desgn="Column" size="26">Degree/Diploma/Certificate</Entry>
<Entry coord="2.4" colno="2" of="4" desgn="Column" size="11">Institution</Entry>
<Entry coord="3.4" colno="3" of="4" desgn="Column" size="14">Date Conferred</Entry>
<Entry coord="3.4" colno="3" of="4" desgn="Column" size="9">(mm/yyyy)</Entry>
<Entry coord="4.4" colno="4" of="4" desgn="Column" size="15">SAQA Evaluated?</Entry>
<Entry coord="4.4" colno="4" of="4" desgn="Column" size="25">(If not SA qualification)</Entry>
</Segment>
<!-- delete -->
</Section>

夸尔
我
影响
学历
(最近的第一次)
学位/文凭/证书
机构
授予日期
(年月日)
SAQA评估?
(如果不是SA资格)
对父(段)元素进行额外处理的预期输出:

<!-- deleted prior input xml -->
<Segment coord="1.25" rowno="1" of="25" frags="3" size="14">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<Segment coord="2.25" rowno="2" of="25" frags="2" size="43">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<Segment coord="3.25" rowno="3" of="25" frags="6" size="100">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<!-- deleted rest of input xml -->

试试这个XSLT1.0样式表(XSLT2.0版本会简单得多):


在xslt1和XSL2中都有效,但只有在以下情况下才有效:如果两个条目的父项和坐标相同,则应折叠它们

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

    <xsl:key name="entry-by-coord" match="Entry" use="concat(generate-id(parent::*), '||', @coord)"/>

    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Entry">
        <xsl:if test="generate-id()=generate-id(key('entry-by-coord', concat(generate-id(parent::*), '||', @coord))[1])">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('entry-by-coord', concat(generate-id(parent::*), '||', @coord))/text()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>


您使用的XSLT版本是什么?1.0还是2.0?以上两种方法都适用于我的xml输入,事实上,它们适用于整个输入,而不仅仅是片段。他们的比较提供了一些有关XSLT特性集和与之配套的设计模式的见解。方法2显然更易于重用,因为它较少依赖元素层次结构文本。谢谢大家。(是的,我正在寻找一种Xslt1解决方案,这些响应支持这种解决方案。)第一种方法依赖于条目元素的顺序,也就是说,它适用于1,1,2,2,3,但实际上不适用于2,1,2,3,1。如果我可以让你们更进一步地探索这种模式或方法的更普遍的用途,如果我想在连接之外做更多的处理,人们会如何扩展这个答案?假设我们想为每个文本片段的字符串长度设置一个属性,但也要使用它们的总和在父级设置相同的属性,并且还可以将子测试片段的数量作为父级属性。我正在将修改后的XML输入发布到编辑后的原始问题中。各位,请撤回以上进一步的探索查询。这不是一个格式良好的查询。因为折叠转换使输入片段计数无效。此外,发现答案2属于明钦族分组模式,有很好的文档记录,甚至在我2001年的dog-eared Kay的第二版.XSLT-Ref中也有记录,因此无需回答。版主,请退出,谢谢
<!-- deleted prior input xml -->
<Segment coord="1.25" rowno="1" of="25" frags="3" size="14">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<Segment coord="2.25" rowno="2" of="25" frags="2" size="43">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<Segment coord="3.25" rowno="3" of="25" frags="6" size="100">
<!-- deleted collapsed Entries as transformed -->
</Segment>
<!-- deleted rest of input xml -->
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform template -->
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Segment">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="Entry[not(@coord = preceding-sibling::Entry/@coord)]">
            <xsl:variable name="Coord" select="@coord"/>
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:for-each select="../Entry[@coord = $Coord]">
                    <xsl:value-of select="."/>
                </xsl:for-each>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
</xsl:transform>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

    <xsl:key name="entry-by-coord" match="Entry" use="concat(generate-id(parent::*), '||', @coord)"/>

    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Entry">
        <xsl:if test="generate-id()=generate-id(key('entry-by-coord', concat(generate-id(parent::*), '||', @coord))[1])">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('entry-by-coord', concat(generate-id(parent::*), '||', @coord))/text()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>