我需要一个XSL转换来使用来自祖先的数据插入所选节点的子元素

时间:2016-12-30 18:24:37

标签: xml xslt

我的XML看起来像这样:

<SCL>
  <IED name="D60_220SW1">
    <AccessPoint name="S1">
      <Server>
        <LDevice inst="Master">
          <LN0 lnClass="LLN0" inst="" lnType="LLN0_0">
            <ReportControl name="URCB01" rptID="XYZ" >
              <TrgOps dchg="true" />
              <OptFields configRef="true" />
             <RptEnabled max="1" />
            </ReportControl>
            <ReportControl name="URCB02" rptID="PAC" datSet="PAC" >
              <TrgOps dchg="true" qchg="true" period="true" />
              <OptFields configRef="true" />
             <RptEnabled max="1" />
            </ReportControl>
          </LN0>
        </LDevice>
      </Server>
    </AccessPoint>
  </IED>
</SCL>

我需要一个转换来选择ReportControl所有@rptID="PAC"个节点,并插入RptEnabled节点的子节点,其属性值取决于{{name属性的值1}}祖先节点。

结果应如下所示:

IED

插入的<SCL> <IED name="D60_220SW1"> <AccessPoint name="S1"> <Server> <LDevice inst="Master"> <LN0 lnClass="LLN0" inst="" lnType="LLN0_0"> <ReportControl name="URCB01" rptID="XYZ" > <TrgOps dchg="true" /> <OptFields configRef="true" /> <RptEnabled max="1" /> </ReportControl> <ReportControl name="URCB02" rptID="PAC" datSet="PAC" > <TrgOps dchg="true" qchg="true" period="true" /> <OptFields configRef="true" /> <RptEnabled max="1" > <ClientLN iedName="APACC_1" apRef="S2" ldInst="LD0" lnClass="ITCI" lnInst="1" /> </RptEnabled> </ReportControl> </LN0> </LDevice> </Server> </AccessPoint> </IED> </SCL> 节点上的iedNameapRef属性的值由ClientLN祖先节点上的name属性的值确定。像这样(我用C#伪代码来说明):

IED

我确信这是可行的,但我无法弄清楚如何,而且我无法找到适用的例子。

1 个答案:

答案 0 :(得分:1)

以下XSLT完成了这项工作。但是因为你没有提供生成ClientLN节点的其他属性的规则,所以我(到目前为止)只是从你想要的输出中复制它们。您应该很容易用所需的值填充它们。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" />

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

  <xsl:template match="ReportControl[@rptID = 'PAC']">   <!-- replace special nodes -->
    <xsl:copy>
      <xsl:apply-templates select="node()[not(self::RptEnabled)]|@*" />
      <RptEnabled>
        <xsl:copy-of select="RptEnabled/@*" />
        <ClientLN apRef="S2" ldInst="LD0" lnClass="ITCI" lnInst="1">
          <xsl:attribute name="iedName">
            <xsl:choose>
              <xsl:when test="contains(ancestor::IED/@name,'_220')">APACC_1</xsl:when>
              <xsl:otherwise>APACC_2</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
        </ClientLN>
      </RptEnabled>
    </xsl:copy>    
  </xsl:template>     
</xsl:stylesheet>