xPath XSLT获取父元素及其子元素和孙子元素

时间:2017-08-24 10:03:50

标签: xml xslt xpath

我需要帮助才能像这样更改xml结构

<AcctInqRq>
 <MsgRqHdr>
    <RqUID>86eb9644-decf-4fa2-bd16-6d5403a8660a</RqUID>
    <ChannelId>897</ChannelId>
 </MsgRqHdr>
 <InqInfo>
    <FromAccount>
       <AccountId>11012442</AccountId>
       <AccountCurrency/>
    </FromAccount>
 </InqInfo>
 <RefInfo>
    <RefName>AppCallerName</RefName>
    <RefValue>API_GATEWAY</RefValue>
 </RefInfo>
</AcctInqRq>

到这个

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://www.some.com/esb/inquiry/acct/types" xmlns:core="http://www.some.com/esb/shared/core">
   <soapenv:Header/>
   <soapenv:Body>
      <typ:AcctInqRq>
         <core:MsgRqHdr>
            <core:RqUID>86eb9644-decf-4fa2-bd16-6d5403a8660a</core:RqUID>
            <core:ChannelId>897</core:ChannelId>
         </core:MsgRqHdr>
         <typ:InqInfo>
            <typ:FromAccount>
               <typ:AccountId>11012442</typ:AccountId>
               <typ:AccountCurrency/>
            </typ:FromAccount>
         </typ:InqInfo>
         <core:RefInfo>
            <core:RefName>AppCallerName</core:RefName>
            <core:RefValue>API_GATEWAY</core:RefValue>
         </core:RefInfo>
      </typ:AcctInqRq>
   </soapenv:Body>
</soapenv:Envelope>

这是我目前的xslt

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:typ="http://www.some.com/esb/inquiry/acct/types" 
xmlns:core="http://www.some.com/esb/shared/core" 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" encoding="utf-8"/>
    <xsl:template match="/">
        <soapenv:Envelope>
            <soapenv:Header/>
            <soapenv:Body>
                <xsl:apply-templates/>
            </soapenv:Body>
        </soapenv:Envelope>
    </xsl:template>
    <xsl:template match="AcctInqRq|InqInfo|FromAccount|AccountId|AccountCurrency|ToAccount|AccountId|AccountCurrency|ChequeNo|RetrievalNo|SlipNo">
        <xsl:element name="typ:{local-name()}">
            <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="MsgRqHdr">
        <xsl:for-each select="*"> 
            <xsl:element name="core:{local-name()}">
                <xsl:apply-templates select="@*|node()"/>
            </xsl:element>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

正如您在尝试手动列出每个单个元素标记之前在第二个模板标记中看到的那样,但是耗时。所以现在我想检查父元素,并递归地更改所有子节点,并分别添加前缀。你可以看到我在第三个模板标签中尝试过。但它失败了。 那我该怎么办呢?另外注意,我们可以覆盖某些字段以不遵守上述规则。例如,AccInqRq的根节点应该添加前缀typ,但是它的后代如MsgRqHdr和RefInfo应该添加前缀core。

所以我可能会想到这样的事情(CMIIW)

..upper xsl code..
<xsl:template match="MsgRqHdr | RefInfo | *other parent element to be added prefix core*
</xsl:template>

<xsl:template match="InqInfo| *other parent element to be added prefix typ*
</xsl:template>

<xsl:template match=" *probably add this one to override some field with specific prefix typ*
</xsl:template>

由于

编辑: 还有另一个信息。所有子节点递归的父节点应该有前缀核心,它的前缀 typ 是不可能的。虽然父元素的每个子节点都有typ前缀,但它的子节点有可能具有核心前缀。所以也许我们可以默认为root元素的子元素添加前缀typ,之后我们可以指定哪些子元素应该 core 前缀

2 个答案:

答案 0 :(得分:2)

您可以为其他元素编写模板,并确保设置优先级:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:typ="http://www.some.com/esb/inquiry/acct/types" 
    xmlns:core="http://www.some.com/esb/shared/core" 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

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

    <xsl:template match="/">
        <soapenv:Envelope>
            <soapenv:Header/>
            <soapenv:Body>
                <xsl:apply-templates/>
            </soapenv:Body>
        </soapenv:Envelope>
    </xsl:template>

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

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

</xsl:stylesheet>

答案 1 :(得分:2)

你可以看到它的另一种方式:

XSLT 1.0

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:typ="http://www.some.com/esb/inquiry/acct/types" 
xmlns:core="http://www.some.com/esb/shared/core">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/AcctInqRq">
    <soapenv:Envelope>
        <soapenv:Header/>
        <soapenv:Body>
            <typ:AcctInqRq>
                <xsl:apply-templates select="MsgRqHdr" mode="core"/>
                <xsl:apply-templates select="InqInfo" mode="typ"/>
                <xsl:apply-templates select="RefInfo" mode="core"/>
            </typ:AcctInqRq>
        </soapenv:Body>
    </soapenv:Envelope>
</xsl:template>

<xsl:template match="*" mode="typ">
    <xsl:element name="typ:{local-name()}">
        <xsl:apply-templates mode="typ"/>
    </xsl:element>
</xsl:template>

<xsl:template match="*" mode="core">
    <xsl:element name="core:{local-name()}">
        <xsl:apply-templates mode="core"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>