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

如何使用带条件的XSLT映射在XML中移动节点,xml,xslt,Xml,Xslt,我有一个类似于以下内容的xml: <?xml version="1.0"?> <MATMAS05> <IDOC BEGIN="1"> <EDI_DC40 SEGMENT="1"> <CREDAT>20180822</CREDAT> <CRETIM>180201</CRETIM> <SERIAL>

我有一个类似于以下内容的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>

20180822
180201
20180821134354
005
000000000002000010
0
0
005
E
009
3030
009
1000
005
005
3040
005
1000
005
005
每个
009
3030
005
3040
005
金
我需要将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>
<?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>

20180822
180201
20180821134354
005
000000000002000010
0
0
005
E
009
3030
009
1000
005
009
3030
005
3040
005
1000
005
005
3040
005
每个
005
金
可能的问题是,有时E1MBEWM节点可能不在传入消息中

我尝试使用XSLT,类似于:

    <?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>
<?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:

  • 第一个是根节点,它将浏览每个
    E1MARCM
    节点,并建立一个与匹配节点相等的节点
  • 第二个,对于每个
    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并从中删除,但我可以稍后将其过滤掉。

    谢谢您的建议。我无法真正列出E1MARCM段中的所有字段,因为通常情况下,根据逻辑,它可能有/没有一些字段。所以,我肯定需要复制整个节点,而不在其中列出字段。实际上,在根节点中除了E1MARCM还有其他节点。我只是试图简化示例以使其更易于理解。看起来我过度简化了输入,这就是为什么解决方案仍然需要修改。我有以下(仍然是简化的)输入。这次我列出了我所有的节点,每个节点上都有几个字段。目的是获取所有节点,但将E1MBEWM节点放入适当的E1MARCM节点,其中BWKEY=WERKS。实际上,我可以将E1MBEWM放在它们所在的位置,但在E1MARCM中有一个适当的副本。我会在几分钟内把它作为一个单独的回答添加进来我刚刚用完整的结构更新了这个问题。。。现在它有了所有的节点,我只在每个节点上留下了几个字段。