当前位置: 动力学知识库 > 问答 > 编程问答 >

xml - XSLT to add prefix namespaces of all nodes except few

问题描述:

I Am trying to write XSLT code to add prefix namespaces to all nodes except few.

Sample XML:

 <BatchPrepareDeliverArchive xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="schema">

<BatchInformation>

<RqUId>424000000071256187550913330</RqUId>

<BatchFeedId>CMLTREXT4240</BatchFeedId>

<BatchCount>7</BatchCount>

</BatchInformation>

<BatchDeliverArchive>

<Transactions>

<Transaction>

<TransactionUUID>90022016-01-140000001</TransactionUUID>

<CustomerData>

<GBD_Transactions>

<GBD_Transaction>

<Common_Data>

<Transaction_ID>90022016-01-140000001</Transaction_ID>

</Common_Data>

<Templates>

<Template>

<Template_Name>A21_LETTER_FINAL_NOTICE_OF_CANCELLATION_TPA</Template_Name>

<Transaction_ID>90022016-01-140000001</Transaction_ID>

</Template>

</Templates>

</GBD_Transaction>

</GBD_Transactions>

</CustomerData>

<DocInfo>

<Name>OPERATION NAME</Name>

</DocInfo>

</Transaction>

</Transactions>

</BatchDeliverArchive>

</BatchPrepareDeliverArchive>

I want to add urn prefix to all nodes except GBD_Transactions & its child elements.

I came up with this XSLT:

 <xsl:stylesheet version="1.0" xmlns:urn="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

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

<xsl:template match="*">

<xsl:element name="urn:{local-name()}">

<xsl:apply-templates/>

</xsl:element>

</xsl:template>

<xsl:template match="@*">

<xsl:element name="urn:{local-name()}">

<xsl:value-of select="."/>

</xsl:element>

</xsl:template>

</xsl:stylesheet>

All nodes are getting transformed here, which is not the expected output.

Would appreciate any help on this!

网友答案:

In your template matching "*", you should differentiate like this:

<xsl:template match="*">
    <xsl:choose>
        <xsl:when test="ancestor-or-self::GBD_Transactions">
            <xsl:copy>
                <xsl:apply-templates"/>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:element name="urn:{local-name()}">
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Output will look like this:

<urn:BatchPrepareDeliverArchive xmlns:urn="http://www.w3.org/2001/XMLSchema-instance">
    <urn:BatchInformation>
        <urn:RqUId>424000000071256187550913330</urn:RqUId>
        <urn:BatchFeedId>CMLTREXT4240</urn:BatchFeedId>
        <urn:BatchCount>7</urn:BatchCount>
    </urn:BatchInformation>
    <urn:BatchDeliverArchive>
        <urn:Transactions>
            <urn:Transaction>
                <urn:TransactionUUID>90022016-01-140000001</urn:TransactionUUID>
                <urn:CustomerData>
                    <GBD_Transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                        <GBD_Transaction>
                            <Common_Data>
                                <Transaction_ID>90022016-01-140000001</Transaction_ID>
                            </Common_Data>
                            <Templates>
                                <Template>
                                    <Template_Name>A21_LETTER_FINAL_NOTICE_OF_CANCELLATION_TPA</Template_Name>
                                    <Transaction_ID>90022016-01-140000001</Transaction_ID>
                                </Template>
                            </Templates>
                        </GBD_Transaction>
                    </GBD_Transactions>
                </urn:CustomerData>
                <urn:DocInfo>
                    <urn:Name>OPERATION NAME</urn:Name>
                </urn:DocInfo>
            </urn:Transaction>
        </urn:Transactions>
    </urn:BatchDeliverArchive>
</urn:BatchPrepareDeliverArchive>

Is that what you want?

网友答案:

If you want to ignore GBD_Transactions elements, and its descendants, just add a template to match the relevant nodes, and use the identity template to copy them as-is.

Try adding this template to the XSLT

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

Note that matching on a specific element name has a higher priority than matching on *, so this template should always be used ahead of the more generic one.

By the way, there is an issue with your template that matches "*". You probably change it to this...

<xsl:template match="*">
  <xsl:element name="urn:{local-name()}">
    <xsl:apply-templates select="@*|node()" />
   </xsl:element>
</xsl:template>

This is because <xsl:apply-templates /> is the same as doing <xsl:apply-templates select="node()" /> and so will not select attributes. Thus, your existing template that matches @* would not get called otherwise.

EDIT: If you want to stop the xsi:schemaLocation attribute becoming an element, add this template too (You will need to declare the xsi namespace in the XSLT)

<xsl:template match="@xsi:*">
    <xsl:copy />
</xsl:template>

Or perhaps you don't want any attributes changed to elements? Try this XSLT instead?

<xsl:stylesheet version="1.0"  xmlns:urn="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="*">
    <xsl:element name="urn:{local-name()}">
    <xsl:apply-templates select="@*|node()" />
    </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy />
    </xsl:template>

    <xsl:template match="GBD_Transactions|GBD_Transactions//*|GBD_Transactions//@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
分享给朋友:
您可能感兴趣的文章:
随机阅读: