基于父子关系使用xslt实现xml到xml的转换
我需要将我的xml转换为基于父子关系的另一个xml 下面是我的xml源代码基于父子关系使用xslt实现xml到xml的转换,xslt,xslt-2.0,Xslt,Xslt 2.0,我需要将我的xml转换为基于父子关系的另一个xml 下面是我的xml源代码 <FIXML> <Header> <RequestID>ReqID8942</RequestID> </Header> <Body> <Data> <LimitDetails> <LimitRefNo>L1</LimitRefNo&
<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>
要求8942
L1
根
100
L2
分类1
L1
200
L3
分类2
L2
300
L4
分类3
L3
400
此处,子限制是指基于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>
要求8942
L1
根
100
L2
分类1
L1
200
L3
分类2
L2
300
L4
分类3
L3
400
提前感谢。此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>
<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>
当应用于相同的XML文档(如上)时,会产生相同的正确结果。键的使用肯定更优雅(请参见Dimitre Novatchevs解决方案),但这一解决方案考虑了结构中所需的更改(例如,将
重命名为
并放置
标记):
或者作为Dimitre解决方案的修改,使用键:
<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>
<Limit>
<xsl:apply-templates select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</Limit>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:apply-templates />
<xsl:if test="key('kLD', LimitRefNo)">
<SubLimit>
<xsl:apply-templates select="key('kLD', LimitRefNo)"/>
</SubLimit>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
有一个小问题。我有四个结束标记,但只有三个打开标记。请帮助我。是否有可能从输出xml中删除标记?L4L3hielsnoppe,您答案中的两个转换之一产生编译错误,而第二个转换产生错误的结果。@DimitreNovatchev我对您为什么会出现错误非常感兴趣,因为当我使用PHP或Java测试它们时,这两个转换都能正常工作,除了上面提到的内容之外。@Moorthy我刚刚更新了转换以解释上面提到的内容。这对你有用吗?如果我使用你指导我的XSLT1.0解决方案,我会得到四个打开和关闭标签,但我需要三个打开和关闭标签。请帮助我。如果我使用你提供给我的XSLT2.0解决方案,我会得到一个错误。错误:“if(ParentLimitRefNo/text())和“Sub”else()”中的语法错误。“致命错误:“无法编译样式表”。我需要输出中的一个父标记和三个打开和关闭标记。请帮助我。@Moorthy,您的陈述与答案中所示不符,结果正好包含3个SubLimit
元素。至于“编译样式表”错误,您确定您真的有XSLT2.0处理器吗?我总是验证我的解决方案是否运行并产生正确的结果。事实上,我只是将真实结果复制并粘贴到答案中。我想我使用的是XSLT1.0处理器。我将更新它XSLT2.0,并将很快更新您。我现在根据您的编码策略学习XSLT。非常感谢。@Moorthy,另一个答案的作者要求您接受最好的答案。通过单击答案旁边的复选标记完成接受。由于只有一个答案是可以接受的,并且为了帮助您做出明智的决定,我想强调使用我的代码的一些优点——它更短、基于键——效率更高、更枯燥——不包含单个
或其他XSLT条件指令。您可能没有注意到,我也提供了一个XSLT1.0解决方案,它具有XSLT2.0的所有优点。
<?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>
<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>
<Limit>
<xsl:apply-templates select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</Limit>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:apply-templates />
<xsl:if test="key('kLD', LimitRefNo)">
<SubLimit>
<xsl:apply-templates select="key('kLD', LimitRefNo)"/>
</SubLimit>
</xsl:if>
</xsl:template>
</xsl:stylesheet>