我需要根据父子关系将xml转换为另一个xml。
以下是我的源xml
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</LimitDetails>
</Data>
</Body>
</FIXML>
此处,子限制是指基于ParentLimitRefNo的父限制。父限制是ParentLimitRefNo为空的限制。
下面是我需要根据源xml生成的xml。
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</SubLimit>
</SubLimit>
</SubLimit>
</Limit>
</LimitDetails>
</Data>
</Body>
提前致谢。
答案 0 :(得分:1)
此XSLT 2.0转换(易于转换为XSLT 1.0):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kLD" match="LimitDetails" use="ParentLimitRefNo"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates
select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="vSuf" select=
"if(ParentLimitRefNo/text())
then 'Sub'
else ()
"/>
<xsl:element name="{$vSuf}Limit">
<xsl:apply-templates select="node()|key('kLD', LimitRefNo)"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</LimitDetails>
</Data>
</Body>
</FIXML>
生成想要的正确结果:
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo/>
<ApprovedLimit>100.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</SubLimit>
</SubLimit>
</SubLimit>
</Limit>
</LimitDetails>
</Data>
</Body>
</FIXML>
<强>解释强>:
使用和修改 identity rule 。
使用 key 从LimitDetails
指定LimitRefNo
的所有逻辑子级。
<强> II。 XSLT 1.0解决方案:
这是上述转换到XSLT 1.0的几乎机械翻译 - 只有变量$vSuf
的定义不同:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kLD" match="LimitDetails" use="ParentLimitRefNo"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates
select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="vSuf" select=
"concat('',
substring('Sub',1 div boolean(ParentLimitRefNo/text()))
)"/>
<xsl:element name="{$vSuf}Limit">
<xsl:apply-templates select="node()|key('kLD', LimitRefNo)"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
当应用于同一XML文档(上图)时,会产生相同的正确结果。
答案 1 :(得分:1)
密钥的使用肯定更优雅(参见Dimitre Novatchevs解决方案),但是这个考虑了结构中想要的变化(例如将<LimitDetails />
重命名为<SubLimit />
并放置{{1标签。):
<Limit />
或者使用键修改Dimitre的解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="Data">
<xsl:copy>
<LimitDetails>
<Limit>
<xsl:apply-templates select=".//LimitDetails[./ParentLimitRefNo='']" />
</Limit>
</LimitDetails>
</xsl:copy>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="LimitRefNo" select="./LimitRefNo" />
<xsl:apply-templates select="@*|node()" />
<xsl:if test="../LimitDetails[./ParentLimitRefNo = $LimitRefNo]">
<SubLimit>
<xsl:apply-templates select="../LimitDetails[./ParentLimitRefNo = $LimitRefNo]" />
</SubLimit>
</xsl:if>
</xsl:template>
</xsl:transform>