Copy xml + remove some positional nodes

2019-09-11 22:50发布

问题:

I nee to do something in BizTalk. But it's only xslt so i tagged it as an xslt question.

I have a "multipart" message on input (as you can see in the xml below "root & InputMessagePart_0"

I have the following xml as input.

<s0:Root xmlns:ns0="http://schemas.microsoft.com/BizTalk/2003/aggschema">
<InputMessagePart_0>
    <ns0:parentnode xmlns:ns0="http://schemas.microsoft.com/namespace1" >
        <ns0:childNode attribute1="test" attribute2="test">
            <levelA xmlns="http://schemas.microsoft.com/namespace2"/>
        </ns0:childNode>
        <ns0:childNode2 Name="childNode2">
            <levelA xmlns="http://schemas.microsoft.com/namespace3"/>
        </ns0:childNode2>
        <ns0:ChildNode3 Name="ChildNode3" id="2015-10-08-12.07.37.218960">
            <ns0:levelA Name="levelA">
                <ns0:data Name="Data" id="123456" type="A">
                </ns0:data>
                <ns0:data Name="Data" id="654321" type="B">
                </ns0:data>
                <ns0:levelAA id="910038265">
                    <ns0:repeatingItem id="910568755" >
                        <ns0:comm Name="Communication" id="910041726" numberOfDocuments="3">
                            <ns0:group Name="Group" id="12">
                                <ns0:doc archived="1" id="123" >
                                </ns0:doc>
                                <ns0:doc archived="1" id="321" >
                                </ns0:doc>
                            </ns0:group>
                        </ns0:comm>
                    </ns0:repeatingItem>
                    <ns0:repeatingItem id="123456789" >
                        <ns0:comm Name="Communication" id="910041726" numberOfDocuments="3">
                            <ns0:group conceptName="Group" id="34">
                                <ns0:doc archived="1" id="1234" >
                                </ns0:doc>
                                <ns0:doc archived="1" id="4321" >
                                </ns0:doc>
                            </ns0:group>
                        </ns0:comm>
                    </ns0:repeatingItem>
                    <ns0:repeatingItem id="987654321" >
                        <ns0:comm Name="Communication" id="910041726" numberOfDocuments="3">
                            <ns0:group Name="Group" id="56">
                                <ns0:doc archived="1" id="12345">
                                </ns0:doc>
                            </ns0:group>
                        </ns0:comm>
                    </ns0:repeatingItem>
                </ns0:levelAA>
                <ns0:OtherDoc id="123">
                    <ns0:Content/>
                </ns0:OtherDoc>
                <ns0:OtherDoc id="321">
                    <ns0:Content/>
                </ns0:OtherDoc>
                <ns0:OtherDoc id="1234">
                    <ns0:Content/>
                </ns0:OtherDoc>
                <ns0:OtherDoc id="4321">
                    <ns0:Content/>
                </ns0:OtherDoc>
            </ns0:data>
        </ns0:ChildNode3>
    </ns0:parentnode>
</InputMessagePart_0>
<InputMessagePart_1>
    <ns7:MessageInformation xmlns:ns7="http://Schemas.RepeatingItemMessageInformation">
        <RepeatingItemPosition>1</RepeatingItemPosition>
    </ns7:MessageInformation>
</InputMessagePart_1>

The thing i need in output

<ns0:parentnode xmlns:ns0="http://schemas.microsoft.com/namespace1" >
<ns0:childNode attribute1="test" attribute2="test">
    <levelA xmlns="http://schemas.microsoft.com/namespace2"/>
</ns0:childNode>
<ns0:childNode2 Name="childNode2">
    <levelA xmlns="http://schemas.microsoft.com/namespace3"/>
</ns0:childNode2>
<ns0:ChildNode3 Name="ChildNode3" id="2015-10-08-12.07.37.218960">
    <ns0:levelA Name="levelA">
        <ns0:data Name="Data" id="123456" type="A">
        </ns0:data>
        <ns0:data Name="Data" id="654321" type="B">
        </ns0:data>
        <ns0:levelAA id="910038265">
            <ns0:repeatingItem id="910568755" >
                <ns0:comm Name="Communication" id="910041726" numberOfDocuments="3">
                    <ns0:group Name="Group" id="12">
                        <ns0:doc archived="0" id="123" >
                        </ns0:doc>
                        <ns0:doc archived="0" id="321" >
                        </ns0:doc>
                    </ns0:group>
                </ns0:comm>
            </ns0:repeatingItem>
        </ns0:levelAA>
        <ns0:OtherDoc id="123">
            <ns0:Content/>
        </ns0:OtherDoc>
        <ns0:OtherDoc id="321">
            <ns0:Content/>
        </ns0:OtherDoc>
    </ns0:data>
</ns0:ChildNode3>

I will explain what it needs.

1) Copy everything under the "InputMessagePart_0"

Then the exceptions :)

a) I only need the repeatingItem with a specific position (in the input you see the "InputMessagePart_1/MessageInformation/repeatingItemPosition"). So in output for this example we only need repeatingItem "1". It's always 1 number. So when we loop in a BizTalk orchestration it will be 1 or 2 or 3 or ....

b) Also under "repeatingItem/comm/group/doc" the attribute "archived" should always been set to "0".

c) This is something i don't know if it's possible. In the "OtherDoc" we have some content (base64 generated stuff). Because we removed other repeatingItems not all "Otherdoc" items are needed. Only the ones with same id as in the repeatingItem doc. (But is this even possible to check on the repeating item and then also remove the OtherDoc's that we don't need.

I already tried some stuff. But i can't get it working. Below you can find what i used. But i am not yet (i hope) an xslt expert. :)

  <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 s1" version="1.0"
                xmlns:ns0="http://schemas.microsoft.com/namespace1"
                xmlns:s0="http://schemas.microsoft.com/BizTalk/2003/aggschema"
                xmlns:s7="http://Schemas.RepeatingMessageInformation">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />     

<xsl:template match="node() | @*">
  <xsl:copy>
    <xsl:apply-templates select="node() | @*"/>
  </xsl:copy>
</xsl:template>

<!-- Copy the n-th repeatingItem element-->
<xsl:template match="ns0:repeatingItem[number(s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition/text())]">
  <xsl:apply-templates select="current()"/>
</xsl:template>

<!-- Don't copy the other repeatingItem elements-->
<xsl:template match="ns0:repeatingItem[position()!=s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition/text()]"/>

<xsl:template match="ns0:doc">
  <ns0:doc>
    <xsl:copy-of select="@*[local-name()!='archived']"/>
    <xsl:attribute name="archived">0</xsl:attribute>
  </ns0:doc>
</xsl:template>
</xsl:stylesheet>

回答1:

Inside a predicate the context node changes so match="ns0:repeatingItem[number(s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition/text())]" needs to be match="ns0:repeatingItem[number(/s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition/text())]" to make sure the predicate does not look for a child s0:Root of ns0:repeatingItem.

But I don't see why you need that template at all, if you want to copy that element then the identity transformation template you already have will do the copying. And doing <xsl:apply-templates select="current()"/> would lead to infinite recursion, I think, so that is not likely what you want.

Then correct <xsl:template match="ns0:repeatingItem[position()!=s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition/text()]"/> to <xsl:template match="ns0:repeatingItem[position()!=/s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition]"/>.

Finally I think you want to add

<xsl:template match="ns0:ChildNode3/ns0:levelA/ns0:OtherDoc[not(@id = ancestor::ns0:ChildNode3/descendant::ns0:repeatingItem[number(/s0:Root/InputMessagePart_1/s7:MessageInformation/repeatingItemPosition)]//ns0:OtherDoc/@id)]"/>

Taking the suggestions together and fixing some issues with element names or namespace names I get

<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 " version="1.0"
                xmlns:ns0="http://schemas.microsoft.com/namespace1"
                xmlns:s0="http://schemas.microsoft.com/BizTalk/2003/aggschema"
                xmlns:s7="http://Schemas.RepeatingItemMessageInformation">

<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes"/>     

<xsl:strip-space elements="*"/>

<xsl:template match="node() | @*">
  <xsl:copy>
    <xsl:apply-templates select="node() | @*"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="s0:Root">
    <xsl:apply-templates select="InputMessagePart_0/node()"/>
</xsl:template>

<!-- Don't copy the other repeatingItem elements-->
<xsl:template match="ns0:repeatingItem[position()!=/s0:Root/InputMessagePart_1/s7:MessageInformation/RepeatingItemPosition]"/>

<xsl:template match="ns0:doc">
  <ns0:doc>
    <xsl:copy-of select="@*[local-name()!='archived']"/>
    <xsl:attribute name="archived">0</xsl:attribute>
  </ns0:doc>
</xsl:template>

<xsl:template match="ns0:ChildNode3/ns0:levelA/ns0:OtherDoc[not(@id = ancestor::ns0:ChildNode3/descendant::ns0:repeatingItem[number(/s0:Root/InputMessagePart_1/s7:MessageInformation/RepeatingItemPosition)]//ns0:doc/@id)]"/>

</xsl:stylesheet>

Online at http://xsltransform.net/ncdD7kX.