如何使用带有条件的 XSLT 映射在 XML 中移动节点



我有一个类似于这样的xml:

<?xml version="1.0"?>
<MATMAS05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<CREDAT>20180822</CREDAT>
<CRETIM>180201</CRETIM>
<SERIAL>20180821134354</SERIAL>
</EDI_DC40>
<E1MARAM SEGMENT="1">
<MSGFN>005</MSGFN>
<MATNR>000000000002000010</MATNR>
<E1MARA1 SEGMENT="1">
<MAXC>0.000</MAXC>
<MAXC_TOL>0.0</MAXC_TOL>
</E1MARA1>
<E1MAKTM SEGMENT="1">
<MSGFN>005</MSGFN>
<SPRAS>E</SPRAS>
</E1MAKTM>
<E1MARCM SEGMENT="1">
<MSGFN>009</MSGFN>
<WERKS>3030</WERKS>
<E1MARDM SEGMENT="1">
<MSGFN>009</MSGFN>
<LGORT>1000</LGORT>
</E1MARDM>
<E1MPGDM SEGMENT="1">
<MSGFN>005</MSGFN>
</E1MPGDM>
</E1MARCM>
<E1MARCM SEGMENT="1">
<MSGFN>005</MSGFN>
<WERKS>3040</WERKS>
<E1MARDM SEGMENT="1">
<MSGFN>005</MSGFN>
<LGORT>1000</LGORT>
</E1MARDM>
<E1MPGDM SEGMENT="1">
<MSGFN>005</MSGFN>
</E1MPGDM>
</E1MARCM>
<E1MARMM SEGMENT="1">
<MSGFN>005</MSGFN>
<MEINH>EA</MEINH>
</E1MARMM>
<E1MBEWM SEGMENT="1">
<MSGFN>009</MSGFN>
<BWKEY>3030</BWKEY>
</E1MBEWM>
<E1MBEWM SEGMENT="1">
<MSGFN>005</MSGFN>
<BWKEY>3040</BWKEY>
</E1MBEWM>
<E1MLANM SEGMENT="1">
<MSGFN>005</MSGFN>
<ALAND>AU</ALAND>
</E1MLANM>
</E1MARAM>
</IDOC>
</MATMAS05>

我需要将E1MBEWM节点移动到适当的E1MARCM节点中,其中 BWKEY=WERKS

所以,基本上它应该是这样的输出:

<?xml version="1.0"?>
<MATMAS05>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<CREDAT>20180822</CREDAT>
<CRETIM>180201</CRETIM>
<SERIAL>20180821134354</SERIAL>
</EDI_DC40>
<E1MARAM SEGMENT="1">
<MSGFN>005</MSGFN>
<MATNR>000000000002000010</MATNR>
<E1MARA1 SEGMENT="1">
<MAXC>0.000</MAXC>
<MAXC_TOL>0.0</MAXC_TOL>
</E1MARA1>
<E1MAKTM SEGMENT="1">
<MSGFN>005</MSGFN>
<SPRAS>E</SPRAS>
</E1MAKTM>
<E1MARCM SEGMENT="1">
<MSGFN>009</MSGFN>
<WERKS>3030</WERKS>
<E1MARDM SEGMENT="1">
<MSGFN>009</MSGFN>
<LGORT>1000</LGORT>
</E1MARDM>
<E1MPGDM SEGMENT="1">
<MSGFN>005</MSGFN>
</E1MPGDM>
<E1MBEWM SEGMENT="1">
<MSGFN>009</MSGFN>
<BWKEY>3030</BWKEY>
</E1MBEWM>
</E1MARCM>
<E1MARCM SEGMENT="1">
<MSGFN>005</MSGFN>
<WERKS>3040</WERKS>
<E1MARDM SEGMENT="1">
<MSGFN>005</MSGFN>
<LGORT>1000</LGORT>
</E1MARDM>
<E1MPGDM SEGMENT="1">
<MSGFN>005</MSGFN>
</E1MPGDM>
<E1MBEWM SEGMENT="1">
<MSGFN>005</MSGFN>
<BWKEY>3040</BWKEY>
</E1MBEWM>
</E1MARCM>
<E1MARMM SEGMENT="1">
<MSGFN>005</MSGFN>
<MEINH>EA</MEINH>
</E1MARMM>
<E1MLANM SEGMENT="1">
<MSGFN>005</MSGFN>
<ALAND>AU</ALAND>
</E1MLANM>
</E1MARAM>
</IDOC>
</MATMAS05>

可能的问题是,有时E1MBEWM节点可能不在传入消息中。

我正在尝试使用类似的东西 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="E1MARCM/*[1]">
<xsl:copy-of select="/*/E1MBEWM[1]"/>
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="/*/E1MBEWM[1]"/>
</xsl:stylesheet>

但如果有多个E1MARCM节点,它不会给出所需的结果。我知道我需要为每个周期使用两个,但不确定如何在这里实现它。

你能帮忙吗?

我的建议是具有两个级别(两个模板(的 XSL:

  1. 第一个,对于根节点,将浏览每个E1MARCM节点并构建一个与匹配的节点相等的节点。
  2. 第二个,对于每个E1MARCM节点,将复制满足所需条件的节点E1MBEWM

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <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:template match="/XML">
    <XML>
    <xsl:apply-templates select="E1MARCM"/>
    </XML>
    </xsl:template>
    <xsl:template match="E1MARCM">
    <E1MARCM SEGMENT="{@SEGMENT}">
    <MSGFN><xsl:value-of select="MSGFN"/></MSGFN>
    <WERKS><xsl:value-of select="WERKS"/></WERKS>
    <xsl:variable name="mywerks" select="WERKS"></xsl:variable>
    <xsl:copy-of select="../E1MBEWM[BWKEY=$mywerks]"/>
    </E1MARCM>
    </xsl:template>
    </xsl:stylesheet>
    

(请注意,在将某个节点的值放入上下文节点不同的 xpath 表达式中之前,有必要将某个节点的值存储在临时变量中。

更新

并且,为了泛化属性和子节点,需要第三个目标:

<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="/XML">
<XML>
<xsl:apply-templates select="E1MARCM"/>
</XML>
</xsl:template>
<xsl:template match="E1MARCM">
<E1MARCM>
<xsl:apply-templates select="@*" mode="just-copy"/>
<xsl:apply-templates select="*" mode="just-copy"/>
<xsl:variable name="mywerks" select="WERKS"></xsl:variable>
<xsl:copy-of select="../E1MBEWM[BWKEY=$mywerks]"/>
</E1MARCM>
</xsl:template>
<xsl:template match="*|@*" mode="just-copy">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>

感谢小桑蒂。 我已经设法玩并找到了适合我目的的解决方案:

<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="E1MARCM">
<E1MARCM>
<xsl:apply-templates select="@*" mode="just-copy"/>
<xsl:apply-templates select="*" mode="just-copy"/>
<xsl:variable name="mywerks" select="WERKS"></xsl:variable>
<xsl:copy-of select="../E1MBEWM[BWKEY=$mywerks]"/>
</E1MARCM>
</xsl:template>
<xsl:template match="*|@*" mode="just-copy">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>

我有一些重复,因为现在我E1MARCM和外面都有E1MBEWM,但我以后可以过滤掉它。