XML-XSLT-使用辅助文档和<xsl:next-match>

时间:2018-07-24 21:57:33

标签: xml xslt saxon xslt-3.0

我有以下XML输入文档:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" 
        repName="FirstElementTemp" 
        date="10-05-2001">
    <element1>
        <subElement>
            SomeData
        </subElement>
    </element1>
    <element2>
        <subElement type="2"/>
    </element2>
</report>

我想在<valueIs>元素之前添加一个名为<element1>的新元素,数据来自另一个我用作<xsl:param>的XML输入文件。

所以基本上这是我想要获得的输出:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
        repName="FirstElementTemp"
        date="10-05-2001">
      <valueIs>FIRST DATA</valueIs>
      <element1>
        <subElement>
            SomeData
        </subElement>
      </element1>
      <element2>
            <subElement type="2"/>
      </element2>
</report>

这是我正在使用的XSLT代码(第二个XML文档内联为):

<?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"
  xpath-default-namespace="http://jasperreports.sourceforge.net/jasperreports"
  xmlns:jsp="http://jasperreports.sourceforge.net/jasperreports"
  exclude-result-prefixes="xs jsp"
  expand-text="yes"
  version="3.0">


<xsl:param name="doc2"  xmlns="">
    <secondDoc>
    <elementTemps>
        <elemTemp ID="1" name="FirstElementTemp" />
        <elemTemp ID="2" name="SecondTemplate" />
    </elementTemps>
    <elementReps>
        <elemRep tmpID="1" name="FirstElementRep" >
            <value>FIRST DATA</value>
        </elemRep>
        <elemRep tmpID="2" name="SecondTemplate">
            <value>SECOND DATA</value>
        </elemRep>
    </elementReps>
    </secondDoc>     
  </xsl:param>

<xsl:output indent="yes" cdata-section-elements="cDataElement"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:key name="key1" match="elemTemp" use="@name" xpath-default-namespace=""/>
  <xsl:key name="key2" match="elemRep" use="@tmpID" xpath-default-namespace=""/>

  <xsl:template match="report">
      <xsl:next-match/>
      <xsl:variable name="temp" select="key('key1', @repName, $doc2)"/>
      <xsl:variable name="rep" select="key('key2', $temp/@ID, $doc2)"/>

      <valueIs>
          <xsl:value-of select="$rep/value" xpath-default-namespace=""/>
      </valueIs>

  </xsl:template>

</xsl:stylesheet>

哪个会产生以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
        repName="FirstElementTemp"
        date="10-05-2001">
      <element1>
        <subElement>
            SomeData
        </subElement>
      </element1>
      <element2>
            <subElement type="2"/>
      </element2>
</report>
<valueIs>FIRST DATA</valueIs>

我知道我不能在此处使用<xsl:next-match>,但是由于我正在使用<report>,所以我需要将keys元素作为当前节点,

有什么方法可以专门在<valueIs>文档之前创建<element1>文档吗?我需要将<valueIs>元素保留在<report>元素内,因为该元素是根节点...

谢谢!

Alexandre Jacinto

1 个答案:

答案 0 :(得分:0)

与其依靠<xsl:next-match>来完成所有工作,不如将某些identity-template逻辑放入模板中以复制元素,将模板应用到其属性,插入自定义内容,以及然后将模板应用于子节点:

<xsl:template match="report">
    <xsl:variable name="temp" select="key('key1', @repName, $doc2)"/>
    <xsl:variable name="rep" select="key('key2', $temp/@ID, $doc2)"/>
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <valueIs>
            <xsl:value-of select="$rep/value" xpath-default-namespace=""/>
        </valueIs>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>

或者,您可以更改模板以使其与第一个子元素report/*[1]匹配,然后在从key1中进行选择时调整XPath,以跳至report元素以选择它。 @repName,生成新元素,然后使用xsl:next-match

<xsl:template match="report/*[1]">
    <xsl:variable name="temp" select="key('key1', ../@repName, $doc2)"/>
    <xsl:variable name="rep" select="key('key2', $temp/@ID, $doc2)"/>
    <valueIs>
        <xsl:value-of select="$rep/value" xpath-default-namespace=""/>
    </valueIs>
    <xsl:next-match/>
</xsl:template>