如何根据条件匹配模板?

How to match template based on condition?

这是我的来源 XML,我试图根据 <City>

的值对其进行转换
<?xml version="1.0" encoding="UTF-8"?>
    <Workers>
        <Worker>
            <EmpID>12345</EmpID>
            <City>NYC</City>
            <Allowance>
                <Type>Meal</Type>
                <Amount>150</Amount>
            </Allowance>
            <Allowance>
                <Type>Gym</Type>
                <Amount>200</Amount>
            </Allowance>
        </Worker>
        <Worker>
            <EmpID>56789</EmpID>
            <City>SFO</City>
            <Base>
                <BaseType>General</BaseType>
                <BaseAmount>1000</BaseAmount>
            </Base>
        </Worker>
        
        <Worker>
            <EmpID>18978</EmpID>
            <City>LAX</City>
            <Base>
                <BaseType>General</BaseType>
                <BaseAmount>3000</BaseAmount>
            </Base>
        </Worker>    
    </Workers>

我正在尝试如下转换。如果 <City> 的值为 NYCSFO

,则无需应用转换
<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
        <m:GetQuotationResponse xmlns:m = "http://www.example.com">
            <m:Worker>12345</m:Worker>
            <m:Location>NYC</m:Location>
            <m:Expense>
                <m:ExpenseType>Meal</m:ExpenseType>
                <m:Amount>150</m:Amount>
            </m:Expense>
            <m:Expense>
                <m:ExpenseType>Gym</m:ExpenseType>
                <m:Amount>200</m:Amount>
            </m:Expense>
        </m:GetQuotationResponse>
    </SOAP-ENV:Body>


    <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
        <m:GetQuotationResponse xmlns:m = "http://www.example.com">
            <m:Worker>56789</m:Worker>
            <m:Location>SFO</m:Location>
            <m:Expense>
                <m:ExpenseType>General</m:ExpenseType>
                <m:Amount>1000</m:Amount>
            </m:Expense>
        </m:GetQuotationResponse>
    </SOAP-ENV:Body>
</Root>

这是我的尝试

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
    xmlns:m = "http://www.example.com"
    exclude-result-prefixes="xs m SOAP-ENV"
    version="2.0">
    <xsl:output method="xml" indent="yes"/>
     
    
    <xsl:template match="Worker[City='NYC']">
      <Root>
        <SOAP-ENV:Body xmlns:m = "http://www.example.com">
            <m:GetQuotationResponse>
                <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                <m:Location><xsl:value-of select="City"/></m:Location>
                <xsl:for-each select="Allowance">
                <m:Expense>
                    <m:ExpenseType><xsl:value-of select="Type"/></m:ExpenseType>            
                    <m:Amount><xsl:value-of select="Amount"/></m:Amount>
                </m:Expense>                
                </xsl:for-each>
            </m:GetQuotationResponse>
        </SOAP-ENV:Body>           
      </Root>
    </xsl:template>
    
    <xsl:template match="Worker[City='SFO']">
        <Root>        
            <SOAP-ENV:Body xmlns:m = "http://www.example.com">
            <m:GetQuotationResponse>
                <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                <m:Location><xsl:value-of select="City"/></m:Location>
                <xsl:for-each select="Base">
                    <m:Expense>
                        <m:ExpenseType><xsl:value-of select="BaseType"/></m:ExpenseType>            
                        <m:Amount><xsl:value-of select="BaseAmount"/></m:Amount>
                    </m:Expense>                
                </xsl:for-each>
            </m:GetQuotationResponse>
        </SOAP-ENV:Body>   
        </Root>        
    </xsl:template>     
                 
</xsl:stylesheet>

我有两个(或更多)问题

当前输出

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
        <m:GetQuotationResponse xmlns:m="http://www.example.com">
            <m:Worker>12345</m:Worker>
            <m:Location>NYC</m:Location>
            <m:Expense>
                <m:ExpenseType>Meal</m:ExpenseType>
                <m:Amount>150</m:Amount>
            </m:Expense>
            <m:Expense>
                <m:ExpenseType>Gym</m:ExpenseType>
                <m:Amount>200</m:Amount>
            </m:Expense>
        </m:GetQuotationResponse>
    </SOAP-ENV:Body>
</Root>
<Root>
    <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
        <m:GetQuotationResponse xmlns:m="http://www.example.com">
            <m:Worker>56789</m:Worker>
            <m:Location>SFO</m:Location>
            <m:Expense>
                <m:ExpenseType>General</m:ExpenseType>
                <m:Amount>1000</m:Amount>
            </m:Expense>
        </m:GetQuotationResponse>
    </SOAP-ENV:Body>
</Root>
18978
LAX
General
3000

使用 xslt 2.0xslt 3.0 获得此工作的任何帮助将不胜感激。谢谢

我发布了 Martin Honnen 建议的第一个解决方案。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
    xmlns:m = "http://www.example.com"
    exclude-result-prefixes="xs m SOAP-ENV"
    version="2.0">
    <xsl:output method="xml" indent="yes"/>
     
    
            
    <xsl:template match="Workers">
        <Root>
            <xsl:apply-templates/>
        </Root>
    </xsl:template>
    
    <xsl:template match="Worker[City='NYC']">
        
            <SOAP-ENV:Body xmlns:m = "http://www.example.com">
                <m:GetQuotationResponse>
                    <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                    <m:Location><xsl:value-of select="City"/></m:Location>
                    <xsl:for-each select="Allowance">
                        <m:Expense>
                            <m:ExpenseType><xsl:value-of select="Type"/></m:ExpenseType>            
                            <m:Amount><xsl:value-of select="Amount"/></m:Amount>
                        </m:Expense>                
                    </xsl:for-each>
                </m:GetQuotationResponse>
            </SOAP-ENV:Body>           
        
    </xsl:template>
    
    <xsl:template match="Worker[City='SFO']">
               
            <SOAP-ENV:Body xmlns:m = "http://www.example.com">
                <m:GetQuotationResponse>
                    <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                    <m:Location><xsl:value-of select="City"/></m:Location>
                    <xsl:for-each select="Base">
                        <m:Expense>
                            <m:ExpenseType><xsl:value-of select="BaseType"/></m:ExpenseType>            
                            <m:Amount><xsl:value-of select="BaseAmount"/></m:Amount>
                        </m:Expense>                
                    </xsl:for-each>
                </m:GetQuotationResponse>
            </SOAP-ENV:Body>   
           
    </xsl:template> 
    
    <xsl:template match="Worker[not(City = ('SFO', 'NYC'))]"/>
                 
</xsl:stylesheet>

这是替代解决方案returns。我不确定如何修改此解决方案以获得预期输出,因为 City='SFO' 具有与 City='NYC'

不同的兄弟节点 <Base>
<?xml version="1.0" encoding="UTF-8"?>
<Root>
   <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
      <m:GetQuotationResponse xmlns:m="http://www.example.com">
         <m:Worker>12345</m:Worker>
         <m:Location>NYC</m:Location>
         <m:Expense>
            <m:ExpenseType>Meal</m:ExpenseType>
            <m:Amount>150</m:Amount>
         </m:Expense>
         <m:Expense>
            <m:ExpenseType>Gym</m:ExpenseType>
            <m:Amount>200</m:Amount>
         </m:Expense>
      </m:GetQuotationResponse>
   </SOAP-ENV:Body>
   <SOAP-ENV:Body xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope">
      <m:GetQuotationResponse xmlns:m="http://www.example.com">
         <m:Worker>56789</m:Worker>
         <m:Location>SFO</m:Location>
      </m:GetQuotationResponse>
   </SOAP-ENV:Body>
</Root>

输出中缺少以下部分

    <m:Expense>
        <m:ExpenseType>General</m:ExpenseType>
        <m:Amount>1000</m:Amount>
    </m:Expense>

@Martin Honnen 建议的替代解决方案经过一些小的调整也可以提供所需的输出。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
    xmlns:m = "http://www.example.com"
    exclude-result-prefixes="xs m SOAP-ENV"
    version="2.0">
    <xsl:output method="xml" indent="yes"/>   
    
    <xsl:template match="Workers">
        <Root>
            <xsl:apply-templates select="Worker[City = ('SFO', 'NYC')]"/>
        </Root>
    </xsl:template>
    
    <xsl:template match="Worker">
        
        <SOAP-ENV:Body xmlns:m = "http://www.example.com">
            <m:GetQuotationResponse>
                <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                <m:Location><xsl:value-of select="City"/></m:Location>
                <xsl:for-each select="Allowance">
                    <m:Expense>
                        <m:ExpenseType><xsl:value-of select="Type"/></m:ExpenseType>            
                        <m:Amount><xsl:value-of select="Amount"/></m:Amount>
                    </m:Expense>                
                </xsl:for-each>
                
                <xsl:for-each select="Base"> <!-- This part was included to get desired output without having to use more than one templates -->
                    <m:Expense>
                        <m:ExpenseType><xsl:value-of select="BaseType"/></m:ExpenseType>            
                        <m:Amount><xsl:value-of select="BaseAmount"/></m:Amount>
                    </m:Expense>                
                </xsl:for-each>
                
            </m:GetQuotationResponse>
        </SOAP-ENV:Body>           
    </xsl:template> 

</xsl:stylesheet>

从模板开始

<xsl:template match="Workers">
  <Root>
    <xsl:apply-templates/>
  </Root>
</xsl:template>

然后使用单个模板将您选择的 Worker 映射到 SOAP 主体,例如<xsl:template match="Worker[City = ('SFO', 'NYC')]"><xsl:template match="Worker[City = 'SFO'] | Worker[City = 'NYC']">,如果您愿意。

对于其他 Worker,设置一个空模板,例如<xsl:template match="Worker[not(City = ('SFO', 'NYC'))]"/>.

作为替代方案,您当然可以只使用匹配 Worker 的模板来映射到 SOAP 主体,并在我展示的第一个模板的 apply-templates 中进行所需的选择,即将其更改为 <xsl:apply-templates select="Worker[City = ('SFO', 'NYC')]"/>,这样您还可以确保只处理想要的 Worker,例如

<xsl:template match="Workers">
  <Root>
    <xsl:apply-templates select="Worker[City = ('SFO', 'NYC')]"/>
  </Root>
</xsl:template>


<xsl:template match="Worker">
    
        <SOAP-ENV:Body xmlns:m = "http://www.example.com">
            <m:GetQuotationResponse>
                <m:Worker><xsl:value-of select="EmpID"/></m:Worker>
                <m:Location><xsl:value-of select="City"/></m:Location>
                <xsl:for-each select="Allowance">
                    <m:Expense>
                        <m:ExpenseType><xsl:value-of select="Type"/></m:ExpenseType>            
                        <m:Amount><xsl:value-of select="Amount"/></m:Amount>
                    </m:Expense>                
                </xsl:for-each>
            </m:GetQuotationResponse>
        </SOAP-ENV:Body>           
    
</xsl:template>