使用XSLT将值从一个元素添加到另一个元素

时间:2015-01-12 18:58:08

标签: xml xslt

我有一个源XML文件,如下所示:

<section name="Test" code="" type="Table" fundid="15" subtype="SOI1" style="" xmlns="http://composition.bowne.com/2010/v4">
  <table xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" accountperiod="2014-07-31" accountperiodtype="0" code="I2" name="Holdings" fundid="15" type="" cols="2">
    <colspec colnum="1" colname="1" />
    <colspec colnum="2" colname="2" />
    <tbody>
      <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="621" hierarchykey="989">
        <td colname="1">
          <datapoint type="Regular" subtype="" name="Caption" value="Health Care Equipment &amp; Supplies" display="always">Health Care Equipment &amp; Supplies</datapoint>
        </td>
        <td colname="2">
          <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="16.6" display="always">16.6</datapoint>
        </td>
      </tr>
      <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="623" hierarchykey="989">
        <td colname="1">
          <datapoint type="Literal" subtype="Custom" name="All Others*" value="All Others*" display="always">All Others*</datapoint>
        </td>
        <td colname="2">
          <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="1.5" display="always">[~PONT]1.5[#~PONT]</datapoint>     (Line A)
        </td>
      </tr>
      <tr type="otherassets" level="1" itemtype="otherassets" hierarchykey="858">
        <td colname="1">
          <datapoint type="Literal" subtype="Custom" name="Other Assets" value="Other Assets" display="always">Other Assets</datapoint>
        </td>
        <td colname="2">
          <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="0.1" display="always">[~PONT]0.1[#~PONT]</datapoint>     (Line B)
        </td>
      </tr>
    </tbody>
  </table>
</section>

我想做的是从(B行)的[~PONT]和[#〜PONT]标签之间取0.1,并将其添加到[~PONT]和[#〜PONT]标签之间的1.5在(线A)上,然后抑制包含(线B)的节点。生成的XML应如下所示:

<section name="Test" code="" type="Table" fundid="15" subtype="SOI1" style="" xmlns="http://composition.bowne.com/2010/v4">
  <table xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" accountperiod="2014-07-31" accountperiodtype="0" code="I2" name="Holdings" fundid="15" type="" cols="2">
    <colspec colnum="1" colname="1" />
    <colspec colnum="2" colname="2" />
    <tbody>
      <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="621" hierarchykey="989">
        <td colname="1">
          <datapoint type="Regular" subtype="" name="Caption" value="Health Care Equipment &amp; Supplies" display="always">Health Care Equipment &amp; Supplies</datapoint>
        </td>
        <td colname="2">
          <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="16.6" display="always">16.6</datapoint>
        </td>
      </tr>
      <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="623" hierarchykey="989">
        <td colname="1">
          <datapoint type="Literal" subtype="Custom" name="All Others*" value="All Others*" display="always">All Others*</datapoint>
        </td>
        <td colname="2">
          <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="1.6" display="always">[~PONT]1.6[#~PONT]</datapoint>
        </td>
      </tr>
    </tbody>
  </table>
</section>

我知道我可以通过使用类似的东西来隔离数值:

<xsl:variable name="Value1" select="substring-before(substring-after(string(.),'[~PONT]'),'[#~PONT]')"/>

不幸的是,关于我所知道的一切。如果这个问题看起来很模糊,我很难道歉,这很难解释,所以请向我询问更多细节。提前感谢任何建议。顺便说一下,我正在使用XSLT版本1。

2 个答案:

答案 0 :(得分:2)

我不确定这是否符合要求,因为它们有点不明确,但是遵循XSLT

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:tab="http://composition.bowne.com/2010/v4" version="1.0">
 <xsl:output method="html" doctype-public="XSLT-compat" 
  omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
 <xsl:strip-space elements="*"/>
  <xsl:template match="/">
    <xsl:apply-templates/> 
  </xsl:template>
  <xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="tab:datapoint[parent::*/preceding-sibling::*/tab:datapoint[@value='All Others*']]/@value">
    <xsl:attribute name="value">
      <xsl:value-of select="sum(.) + 
          sum(//tab:tr[@type='otherassets']/tab:td[2]/tab:datapoint/@value)"/>
      </xsl:attribute>  
  </xsl:template>
  <xsl:template match="tab:datapoint[parent::*/preceding-sibling::*/tab:datapoint[@value='All Others*']]/text()">
    <xsl:text>[~PONT]</xsl:text>
    <xsl:value-of select="sum(./parent::*/@value) + sum(//tab:tr[@type='otherassets']/tab:td[2]/tab:datapoint/@value)"/>
    <xsl:text>[#~PONT]</xsl:text>
  </xsl:template>
  <xsl:template match="tab:tr[@type='otherassets']"/>
</xsl:transform>

当应用于问题中的输入XML时产生输出

<section xmlns="http://composition.bowne.com/2010/v4" name="Test" code="" type="Table" fundid="15" subtype="SOI1" style="">
 <table xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" accountperiod="2014-07-31" accountperiodtype="0" code="I2" name="Holdings" fundid="15" type="" cols="2">
  <colspec colnum="1" colname="1"></colspec>
  <colspec colnum="2" colname="2"></colspec>
  <tbody>
     <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="621" hierarchykey="989">
        <td colname="1">
           <datapoint type="Regular" subtype="" name="Caption" value="Health Care Equipment &amp; Supplies" display="always">Health Care Equipment &amp; Supplies</datapoint>
        </td>
        <td colname="2">
           <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="16.6" display="always">16.6</datapoint>
        </td>
     </tr>
     <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="623" hierarchykey="989">
        <td colname="1">
           <datapoint type="Literal" subtype="Custom" name="All Others*" value="All Others*" display="always">All Others*</datapoint>
        </td>
        <td colname="2">
           <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="1.6" display="always">[~PONT]1.6[#~PONT]</datapoint>     (Line A)

        </td>
     </tr>
  </tbody>
 </table>

对于这个转换,我在XSLT中添加了作为示例名称空间的输入XML的附加名称空间xmlns="http://composition.bowne.com/2010/v4"

xmlns:tab="http://composition.bowne.com/2010/v4"

模板匹配

<xsl:template match="tab:tr[@type='otherassets']"/>

为空并删除此tr

模板匹配

<xsl:template match="tab:datapoint[parent::*/preceding-sibling::*
                    /tab:datapoint[@value='All Others*']]/@value">

value属性的值更改为此值的总和以及datapoint的{​​{1}}的值:

tr[@type='otherassets']

要更改文字,模板会与此<xsl:attribute name="value"> <xsl:value-of select="sum(.) + sum(//tab:tr[@type='otherassets']/tab:td[2]/tab:datapoint/@value)"/> </xsl:attribute>

text()相匹配
tr

不使用问题中建议的<xsl:template match="tab:datapoint[parent::*/preceding-sibling::* /tab:datapoint[@value='All Others*']]/text()"> substring-before(),而是使用数据点的substring-after()属性的值来获取两个值的总和:

value

这是基于 <xsl:value-of select="sum(./parent::*/@value) + sum(//tab:tr[@type='otherassets']/tab:td[2]/tab:datapoint/@value)"/> 属性的值与value之间文本中的值相同的假设。

更新:对于评论中的问题,如果匹配模式中的文字不是硬编码但参数:

,如何调整此问题

遵循XSLT

[~PONT][#~PONT]

产生相同的结果。

调整两个参数

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tab="http://composition.bowne.com/2010/v4" version="1.0">
<xsl:output method="html" doctype-public="XSLT-compat" 
 omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
 <xsl:strip-space elements="*"/>
  <xsl:param name="otherRemove" select="'otherassets'"/>
  <xsl:param name="otherKeep" select="'All Others*'"/>
  <xsl:template match="/">
    <xsl:apply-templates/> 
  </xsl:template>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="tab:datapoint[@name='PercentOfNetAssets']/@value">
    <xsl:choose>
      <xsl:when test="parent::tab:datapoint/parent::tab:td
                /preceding-sibling::*/tab:datapoint[@value=$otherKeep]">
        <xsl:attribute name="value">
          <xsl:value-of select="sum(.) + 
           sum(//tab:tr[@type=$otherRemove]/tab:td[2]/tab:datapoint/@value)"/>
        </xsl:attribute> 
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template match="tab:datapoint[@name='PercentOfNetAssets']/text()">
    <xsl:choose>
      <xsl:when test="parent::tab:datapoint/parent::tab:td
                /preceding-sibling::*/tab:datapoint[@value=$otherKeep]">
        <xsl:text>[~PONT]</xsl:text>
          <xsl:value-of select="sum(./parent::*/@value) + 
             sum(//tab:tr[@type=$otherRemove]/tab:td[2]/tab:datapoint/@value)"/>
        <xsl:text>[#~PONT]</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template match="tab:tr">
    <xsl:choose>
       <xsl:when test="@type=$otherRemove"/>
       <xsl:otherwise>
         <xsl:copy>
           <xsl:apply-templates select="@*|node()"/>
         </xsl:copy>
       </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:transform>

已添加。
要删除该行,现在模板将匹配所有 <xsl:param name="otherRemove" select="'otherassets'"/> <xsl:param name="otherKeep" select="'All Others*'"/>

tr

如果<xsl:template match="tab:tr"> <xsl:choose> <xsl:when test="@type=$otherRemove"/> <xsl:otherwise> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:template> 属性值tr @type没有$otherRemove,则复制所有otherassets。 匹配text()@value的模板以相同的方式进行调整:

<xsl:template match="tab:datapoint[@name='PercentOfNetAssets']/text()">

<xsl:template match="tab:datapoint[@name='PercentOfNetAssets']/@value">

两个模板都会检入<xsl:choose>

<xsl:when test="parent::tab:datapoint/parent::tab:td
          /preceding-sibling::*/tab:datapoint[@value=$otherKeep]">

对于与$otherKeep的第一个版本的硬编码模板匹配模式相同的条件是All Others*,调整匹配元素的值并复制所有其他text()和{{1元素。

答案 1 :(得分:1)

  1. 从身份转换开始,以便默认情况下所有节点都是 复制到输出。
  2. 然后添加覆盖以取消您不再需要的tr。在 在下面的示例中,我键入了@itemtype='otherassets'
  3. 然后为datapoint添加覆盖以接收记录。在 在下面的示例中,我键入了categorykeyitemtypecolname。您可能希望根据您的完整示例进行调整/概括, 但是这个标准适用于你的样本输入,应该给你一个 感受到所需要的东西。
  4. 此XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:b="http://composition.bowne.com/2010/v4">
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="b:tr[@categorykey='623']/b:td[@colname='2']/b:datapoint">
        <xsl:variable name="v1"
                      select="substring-before(substring-after(string(.),'[~PONT]'),'[#~PONT]')"/>
        <xsl:variable name="otherdp"
                      select="../../../b:tr[@itemtype='otherassets']/b:td[@colname='2']/b:datapoint"/>
        <xsl:variable name="v2"
                      select="substring-before(substring-after(string($otherdp),'[~PONT]'),'[#~PONT]')"/>
        <xsl:copy>[~PONT]<xsl:value-of select="$v1 + $v2"/>[#~PONT]</xsl:copy>
      </xsl:template>
    
      <xsl:template match="b:tr[@itemtype='otherassets']"/>
    
    </xsl:stylesheet>
    

    产生所需的XML输出:

    <?xml version="1.0" encoding="UTF-8"?><section xmlns="http://composition.bowne.com/2010/v4" name="Test" code="" type="Table" fundid="15" subtype="SOI1" style="">
      <table xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" accountperiod="2014-07-31" accountperiodtype="0" code="I2" name="Holdings" fundid="15" type="" cols="2">
        <colspec colnum="1" colname="1"/>
        <colspec colnum="2" colname="2"/>
        <tbody>
          <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="621" hierarchykey="989">
            <td colname="1">
              <datapoint type="Regular" subtype="" name="Caption" value="Health Care Equipment &amp; Supplies" display="always">Health Care Equipment &amp; Supplies</datapoint>
            </td>
            <td colname="2">
              <datapoint type="Regular" subtype="" name="PercentOfNetAssets" value="16.6" display="always">16.6</datapoint>
            </td>
          </tr>
          <tr type="categoryhead" level="1" itemtype="categoryhead" categorykey="623" hierarchykey="989">
            <td colname="1">
              <datapoint type="Literal" subtype="Custom" name="All Others*" value="All Others*" display="always">All Others*</datapoint>
            </td>
            <td colname="2">
              <datapoint>[~PONT]1.6[#~PONT]</datapoint>
            </td>
          </tr>
    
        </tbody>
      </table>
    </section>