提取子节点以使用各自的父节点创建 XML
extract child node to create XML with respective parent node
我有一个输入 XML 就像下面的结构。
<Root>
<STDS>
<DEPT>111</DEPT>
<COD>123</COD>
<PIN>100</PIN>
</STDS>
<STDS>
<DEPT>222</DEPT>
<COD>234</COD>
<PIN>200</PIN>
<DETS>
<NAM>ABC</NAM>
<AGE>20</AGE>
</DETS>
</STDS>
<STDS>
<DEPT>333</DEPT>
<COD>345</COD>
<PIN>300</PIN>
<DETS>
<NAM>XYZ</NAM>
<AGE>21</AGE>
</DETS>
<DETS>
<NAM>ZZZ</NAM>
<AGE>21</AGE>
</DETS>
</STDS>
</Root>
我正在使用以下代码来解决这个问题。我正在使用一个 for-each 循环将所有 STDS 全部转换为,而另一个 for-each 正在提取子 DETS 并将其与父 DETS 节点合并。但是由于 for-each,它将所有节点放在一起。而子节点 (DETS) 需要位于相应父节点的正下方。
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 userCSharp" version="1.0" xmlns:ns0="Students" xmlns:s0="STDS" xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/s0:Root" />
</xsl:template>
<xsl:template match="/s0:Root">
<ns0:Students>
<xsl:for-each select="s0:Root/s0:STDS">
<Students>
<Department>
<xsl:value-of select="s0:DEPT" />
</Department>
<Code>
<xsl:value-of select="s0:COD" />
</Code>
<Pin>
<xsl:value-of select="s0:PIN" /></Pin>
<Details>
<Name><xsl:value-of select="NAM" /></Name>
<Age><xsl:value-of select="AGE" /></Age>
</Details>
</Students>
</xsl:for-each>
<xsl:for-each select="s0:STDS/s0:DETS">
<Students>
<Department>
<xsl:value-of select="../DEPT" />
</Department>
<Code>
<xsl:value-of select="../COD" />
</Code>
<Pin>
<xsl:value-of select="../PIN" />
</Pin>
<Details>
<Name><xsl:value-of select="s0:NAM" /></Name>
<Age><xsl:value-of select="s0:AGE" /></Age>
</Details>
</Students>
</xsl:for-each>
我得到以下输出。由于for-each,所有提取的节点都在最后。
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
<Details>
<Name>ABC</Name>
<Age>20</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>XYZ</Name>
<Age>21</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>ZZZ</Name>
<Age>21</Age>
</Details>
</Students>
下面是预期的输出。
<Students>
<Department>111</Department>
<Code>123</Code>
<Pin>100</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
<Details>
<Name>ABC</Name>
<Age>20</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>XYZ</Name>
<Age>21</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>ZZZ</Name>
<Age>21</Age>
</Details>
</Students>
这是一个相当奇怪的要求 - 但可以通过以下方式轻松实现:
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:template match="/Root">
<xsl:for-each select="STDS">
<xsl:variable name="common">
<Department>
<xsl:value-of select="DEPT" />
</Department>
<Code>
<xsl:value-of select="COD" />
</Code>
<Pin>
<xsl:value-of select="PIN" />
</Pin>
</xsl:variable>
<!-- DEPARTMENT -->
<Students>
<xsl:copy-of select="$common"/>
</Students>
<!-- STUDENTS -->
<xsl:for-each select="DETS">
<Students>
<xsl:copy-of select="$common"/>
<Details>
<Name>
<xsl:value-of select="NAM" />
</Name>
<Age>
<xsl:value-of select="AGE" />
</Age>
</Details>
</Students>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
请注意,结果是一个 XML 片段(没有单个根元素)。
考虑避免使用多个 xsl:for-each
(通常是使用循环而不是 XSLT 的递归样式的应用层语言的范例)并使用模板有条件地应用 Details 来处理需求节点(如果存在):
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Root">
<xsl:copy>
<xsl:apply-templates select="STDS"/>
</xsl:copy>
</xsl:template>
<xsl:template match="STDS">
<Students>
<Department><xsl:value-of select="DEPT"/></Department>
<Code><xsl:value-of select="COD"/></Code>
<Pin><xsl:value-of select="PIN"/></Pin>
</Students>
<xsl:apply-templates select="DETS"/>
</xsl:template>
<xsl:template match="DETS">
<Students>
<Department><xsl:value-of select="../DEPT"/></Department>
<Code><xsl:value-of select="../COD"/></Code>
<Pin><xsl:value-of select="../PIN"/></Pin>
<Details>
<Name><xsl:value-of select="NAM"/></Name>
<Age><xsl:value-of select="AGE"/></Age>
</Details>
</Students>
</xsl:template>
</xsl:transform>
在 Mapper 中,您需要做的就是通过 Looping Functoid.
将 <DETS>
连接到 <Students>
仅此而已,不需要自定义 xslt。
一个注意事项:根据架构组成,您可能需要从 <STDS>
到 <Student>
的另一个循环 Functoid。尝试不同的组合非常容易。
虽然它们在技术上可能是正确的,但在 BizTalk.
中,Xsl 答案并不是执行此操作的正确方法
我有一个输入 XML 就像下面的结构。
<Root>
<STDS>
<DEPT>111</DEPT>
<COD>123</COD>
<PIN>100</PIN>
</STDS>
<STDS>
<DEPT>222</DEPT>
<COD>234</COD>
<PIN>200</PIN>
<DETS>
<NAM>ABC</NAM>
<AGE>20</AGE>
</DETS>
</STDS>
<STDS>
<DEPT>333</DEPT>
<COD>345</COD>
<PIN>300</PIN>
<DETS>
<NAM>XYZ</NAM>
<AGE>21</AGE>
</DETS>
<DETS>
<NAM>ZZZ</NAM>
<AGE>21</AGE>
</DETS>
</STDS>
</Root>
我正在使用以下代码来解决这个问题。我正在使用一个 for-each 循环将所有 STDS 全部转换为,而另一个 for-each 正在提取子 DETS 并将其与父 DETS 节点合并。但是由于 for-each,它将所有节点放在一起。而子节点 (DETS) 需要位于相应父节点的正下方。
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 userCSharp" version="1.0" xmlns:ns0="Students" xmlns:s0="STDS" xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/s0:Root" />
</xsl:template>
<xsl:template match="/s0:Root">
<ns0:Students>
<xsl:for-each select="s0:Root/s0:STDS">
<Students>
<Department>
<xsl:value-of select="s0:DEPT" />
</Department>
<Code>
<xsl:value-of select="s0:COD" />
</Code>
<Pin>
<xsl:value-of select="s0:PIN" /></Pin>
<Details>
<Name><xsl:value-of select="NAM" /></Name>
<Age><xsl:value-of select="AGE" /></Age>
</Details>
</Students>
</xsl:for-each>
<xsl:for-each select="s0:STDS/s0:DETS">
<Students>
<Department>
<xsl:value-of select="../DEPT" />
</Department>
<Code>
<xsl:value-of select="../COD" />
</Code>
<Pin>
<xsl:value-of select="../PIN" />
</Pin>
<Details>
<Name><xsl:value-of select="s0:NAM" /></Name>
<Age><xsl:value-of select="s0:AGE" /></Age>
</Details>
</Students>
</xsl:for-each>
我得到以下输出。由于for-each,所有提取的节点都在最后。
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
<Details>
<Name>ABC</Name>
<Age>20</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>XYZ</Name>
<Age>21</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>ZZZ</Name>
<Age>21</Age>
</Details>
</Students>
下面是预期的输出。
<Students>
<Department>111</Department>
<Code>123</Code>
<Pin>100</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
</Students>
<Students>
<Department>222</Department>
<Code>234</Code>
<Pin>200</Pin>
<Details>
<Name>ABC</Name>
<Age>20</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>XYZ</Name>
<Age>21</Age>
</Details>
</Students>
<Students>
<Department>333</Department>
<Code>345</Code>
<Pin>300</Pin>
<Details>
<Name>ZZZ</Name>
<Age>21</Age>
</Details>
</Students>
这是一个相当奇怪的要求 - 但可以通过以下方式轻松实现:
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:template match="/Root">
<xsl:for-each select="STDS">
<xsl:variable name="common">
<Department>
<xsl:value-of select="DEPT" />
</Department>
<Code>
<xsl:value-of select="COD" />
</Code>
<Pin>
<xsl:value-of select="PIN" />
</Pin>
</xsl:variable>
<!-- DEPARTMENT -->
<Students>
<xsl:copy-of select="$common"/>
</Students>
<!-- STUDENTS -->
<xsl:for-each select="DETS">
<Students>
<xsl:copy-of select="$common"/>
<Details>
<Name>
<xsl:value-of select="NAM" />
</Name>
<Age>
<xsl:value-of select="AGE" />
</Age>
</Details>
</Students>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
请注意,结果是一个 XML 片段(没有单个根元素)。
考虑避免使用多个 xsl:for-each
(通常是使用循环而不是 XSLT 的递归样式的应用层语言的范例)并使用模板有条件地应用 Details 来处理需求节点(如果存在):
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Root">
<xsl:copy>
<xsl:apply-templates select="STDS"/>
</xsl:copy>
</xsl:template>
<xsl:template match="STDS">
<Students>
<Department><xsl:value-of select="DEPT"/></Department>
<Code><xsl:value-of select="COD"/></Code>
<Pin><xsl:value-of select="PIN"/></Pin>
</Students>
<xsl:apply-templates select="DETS"/>
</xsl:template>
<xsl:template match="DETS">
<Students>
<Department><xsl:value-of select="../DEPT"/></Department>
<Code><xsl:value-of select="../COD"/></Code>
<Pin><xsl:value-of select="../PIN"/></Pin>
<Details>
<Name><xsl:value-of select="NAM"/></Name>
<Age><xsl:value-of select="AGE"/></Age>
</Details>
</Students>
</xsl:template>
</xsl:transform>
在 Mapper 中,您需要做的就是通过 Looping Functoid.
将<DETS>
连接到 <Students>
仅此而已,不需要自定义 xslt。
一个注意事项:根据架构组成,您可能需要从 <STDS>
到 <Student>
的另一个循环 Functoid。尝试不同的组合非常容易。
虽然它们在技术上可能是正确的,但在 BizTalk.
中,Xsl 答案并不是执行此操作的正确方法