XSLT:根据另一个属性的条件更改属性

时间:2018-02-09 09:47:22

标签: xml xslt

虽然有许多类似的问题,但似乎没有一个问题符合我的要求。

我想根据元素的 ean_party 属性更改XML中元素 invoice:transport 属性< EM>发票:保险

输入XML如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<invoice:response xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" language="de" modus="production" xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd">
    <invoice:processing>
        <!--original "from" attribute-->
        <invoice:transport from="7601003000123" to="7601003000456">
            <invoice:via sequence_id="1" via="7601003000789"/>
        </invoice:transport>
    </invoice:processing>
    <invoice:payload copy="false" credit_advice="false" response_timestamp="1515671999" storno="false" type="invoice">
        <invoice:invoice request_date="2018-01-01T00:00:00" request_id="999999" request_timestamp="1515671999"/>
        <invoice:body>
            <invoice:insurance ean_party="7601003000999"/>
        </invoice:body>
    </invoice:payload>
</invoice:response>

输出XML应如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<invoice:response xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" language="de" modus="production" xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd">
    <invoice:processing>
        <!--replaced "from" attribute with ean_party attribute-->
        <invoice:transport from="7601003000999" to="7601003000456">
            <invoice:via sequence_id="1" via="7601003000789"/>
        </invoice:transport>
    </invoice:processing>
    <invoice:payload copy="false" credit_advice="false" response_timestamp="1515671999" storno="false" type="invoice">
        <invoice:invoice request_date="2018-01-01T00:00:00" request_id="999999" request_timestamp="1515671999"/>
        <invoice:body>
            <!--ean_party attribute that matches my condition-->
            <invoice:insurance ean_party="7601003000999"/>
        </invoice:body>
    </invoice:payload>
</invoice:response>

我尝试过从另一篇文章调整XSLT,但我没有工作:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <!--declare condition for transport block-->
    <xsl:variable name="mandant">
        <xsl:choose>
            <xsl:when test="//transport = '7601003000123'">
                <xsl:value-of select="'7601003000999'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="//transport"/>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:variable>
    <!--dynamic template for replacing current value to condition value-->    
    <xsl:template name="value-to-replace">
        <xsl:param name="param.str"/>
        <xsl:param name="param.target"/>
        <xsl:param name="param.replacement"/>
        <xsl:choose>
            <xsl:when test="contains($param.str, $param.target)">                    
                <xsl:value-of select="concat(substring-before($param.str, $param.target), $param.replacement, substring-after($param.str, $param.target))"/>              
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$param.str"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!--replace value in transport block with mandant variable condition-->
    <xsl:template match="@from">
        <xsl:attribute name="{name()}">                                    
            <xsl:call-template name="value-to-replace">                       
                <xsl:with-param name="param.str" select="."/>                       
                <xsl:with-param name="param.target" select="//transport"/>                       
                <xsl:with-param name="param.replacement" select="$mandant"/>                   
            </xsl:call-template>
        </xsl:attribute>                      
    </xsl:template>             
    <!--copy all nodes-->    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>    
</xsl:stylesheet>

谢谢你的支持!

1 个答案:

答案 0 :(得分:0)

您的主要问题在于您如何引用transport元素

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

这里有两个问题......

  1. 您尚未考虑名称空间。在您的输入XML中,transport元素位于命名空间中(通过使用invoice:前缀表示。但您的XSLT正在寻找无命名空间中的transport元素
  2. 表达式是选择transport元素的值,但您需要@from属性的值。
  3. 所以应该是这个......

    <xsl:value-of select="//invoice:transport/@from"/>
    

    试试这个XSLT ......

    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <!--declare condition for transport block-->
    <xsl:variable name="mandant">
        <xsl:choose>
            <xsl:when test="//invoice:transport/@from = '7601003000123'">
                <xsl:value-of select="'7601003000999'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="//invoice:transport/@from"/>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:variable>
    <!--dynamic template for replacing current value to condition value-->    
    <xsl:template name="value-to-replace">
        <xsl:param name="param.str"/>
        <xsl:param name="param.target"/>
        <xsl:param name="param.replacement"/>
        <xsl:choose>
            <xsl:when test="contains($param.str, $param.target)">                    
                <xsl:value-of select="concat(substring-before($param.str, $param.target), $param.replacement, substring-after($param.str, $param.target))"/>              
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$param.str"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <!--replace value in transport block with mandant variable condition-->
    <xsl:template match="@from">
        <xsl:attribute name="{name()}">                                    
            <xsl:call-template name="value-to-replace">                       
                <xsl:with-param name="param.str" select="."/>                       
                <xsl:with-param name="param.target" select="//invoice:transport/@from"/> 
                <xsl:with-param name="param.replacement" select="$mandant"/>                   
            </xsl:call-template>
        </xsl:attribute>                      
    </xsl:template>             
    <!--copy all nodes-->    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>    
    

    但是,我不禁想知道你的XSLT是否过于复杂。如果您只是将一个完整的值替换为另一个,那么我认为您可以根据原始要求将XSLT简化为此...

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:invoice="http://www.forum-datenaustausch.ch/invoice">
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="invoice:transport/@from">
        <xsl:attribute name="{name()}">
          <xsl:value-of select="//invoice:insurance/@ean_party" />
        </xsl:attribute>
      </xsl:template>
    </xsl:stylesheet>