使用 XSLT 基于属性合并 Xml 元素
Merge Xml elements based on attribute using XSLT
我想合并 position 元素并在比较 type 属性后创建一个名为 travel 的新元素。第一个 type="from" 必须与找到的第一个 type="to" 合并,并应继续其余的。
输入
<?xml version="1.0" encoding="UTF-8"?>
<JOB age="0" priority="N">
<container ID="TSTU2345678" TP="4200"/>
<container ID="TSTU3456789" TP="4200"/>
<position refID="Y.Test:AA.01.01.1" name="AA0101.1" type="from"/>
<position refID="Y.Test:AA.01.02.1" name="AA0102.1" type="from"/>
<position refID="Y.Test:AA.02.02.1" name="AA0202.1" type="to"/>
<position refID="Y.Test:AA.02.03.1" name="AA0203.1" type="to"/>
</JOB>
需要输出
<JOB age="0" priority="N">
<Travel FromrefID="Y.Test:AA.01.01.1" Fromname="AA0101.1" TorefID="Y.Test:AA.02.02.1" Toname="AA0202.1"/>
<Travel FromrefID="Y.Test:AA.01.02.1" Fromname="AA0102.1" TorefID="Y.Test:AA.02.03.1" Toname="AA0203.1"/>
</JOB>
到目前为止我已经尝试过什么。它将所有 To 类型添加到 from 元素中。我不确定如何 select 第一个并将其标记为已使用。还有如何更改属性名称。请帮忙。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="position" match="job/position" use="@type" />
<xsl:template match="job">
<xsl:copy>
<xsl:apply-templates select="@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<JOB>
<xsl:apply-templates select="job/@*" />
<xsl:for-each select="key('position','from')">
<Travel>
<xsl:apply-templates select="@*" />
<xsl:for-each select="key('position','to')">
<To>
<xsl:apply-templates select="@*" />
</To>
</xsl:for-each>
</Travel>
</xsl:for-each>
</JOB>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
谢谢。
我建议你这样看:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="to" match="position[@type='to']" use="count(preceding-sibling::position[@type='to'])" />
<xsl:template match="/JOB">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each select="position[@type='from']">
<xsl:variable name="to" select="key('to', position() - 1)" />
<Travel FromrefID="{@refID}" Fromname="{@name}" TorefID="{$to/@refID}" Toname="{$to/@name}"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意,我们在这里假设 "from" 和 "to" 个位置的数量相等(或者至少 "from" 个位置的数量不小于 "from" 个位置的数量"to" 个职位)。
另一种 XSLT 1.0 解决方案
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|position[@type='from']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="position[@type='from']">
<xsl:variable name="fromPos" select="position()"/>
<Travel FromRefId="{@refID}" Fromname="{@name}">
<xsl:apply-templates select="position[@type='to'][position()=$fromPos]"/>
</Travel>
</xsl:template>
<xsl:template match="position[@type='to']">
<xsl:attribute name="TorefID">
<xsl:value-of select="@refID"/>
</xsl:attribute>
<xsl:attribute name="Toname">
<xsl:value-of select="@name"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
我想合并 position 元素并在比较 type 属性后创建一个名为 travel 的新元素。第一个 type="from" 必须与找到的第一个 type="to" 合并,并应继续其余的。
输入
<?xml version="1.0" encoding="UTF-8"?>
<JOB age="0" priority="N">
<container ID="TSTU2345678" TP="4200"/>
<container ID="TSTU3456789" TP="4200"/>
<position refID="Y.Test:AA.01.01.1" name="AA0101.1" type="from"/>
<position refID="Y.Test:AA.01.02.1" name="AA0102.1" type="from"/>
<position refID="Y.Test:AA.02.02.1" name="AA0202.1" type="to"/>
<position refID="Y.Test:AA.02.03.1" name="AA0203.1" type="to"/>
</JOB>
需要输出
<JOB age="0" priority="N">
<Travel FromrefID="Y.Test:AA.01.01.1" Fromname="AA0101.1" TorefID="Y.Test:AA.02.02.1" Toname="AA0202.1"/>
<Travel FromrefID="Y.Test:AA.01.02.1" Fromname="AA0102.1" TorefID="Y.Test:AA.02.03.1" Toname="AA0203.1"/>
</JOB>
到目前为止我已经尝试过什么。它将所有 To 类型添加到 from 元素中。我不确定如何 select 第一个并将其标记为已使用。还有如何更改属性名称。请帮忙。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="position" match="job/position" use="@type" />
<xsl:template match="job">
<xsl:copy>
<xsl:apply-templates select="@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<JOB>
<xsl:apply-templates select="job/@*" />
<xsl:for-each select="key('position','from')">
<Travel>
<xsl:apply-templates select="@*" />
<xsl:for-each select="key('position','to')">
<To>
<xsl:apply-templates select="@*" />
</To>
</xsl:for-each>
</Travel>
</xsl:for-each>
</JOB>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
谢谢。
我建议你这样看:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="to" match="position[@type='to']" use="count(preceding-sibling::position[@type='to'])" />
<xsl:template match="/JOB">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:for-each select="position[@type='from']">
<xsl:variable name="to" select="key('to', position() - 1)" />
<Travel FromrefID="{@refID}" Fromname="{@name}" TorefID="{$to/@refID}" Toname="{$to/@name}"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意,我们在这里假设 "from" 和 "to" 个位置的数量相等(或者至少 "from" 个位置的数量不小于 "from" 个位置的数量"to" 个职位)。
另一种 XSLT 1.0 解决方案
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|position[@type='from']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="position[@type='from']">
<xsl:variable name="fromPos" select="position()"/>
<Travel FromRefId="{@refID}" Fromname="{@name}">
<xsl:apply-templates select="position[@type='to'][position()=$fromPos]"/>
</Travel>
</xsl:template>
<xsl:template match="position[@type='to']">
<xsl:attribute name="TorefID">
<xsl:value-of select="@refID"/>
</xsl:attribute>
<xsl:attribute name="Toname">
<xsl:value-of select="@name"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>