XSLT:仅替换模板中元素的某些子节点,在另一个上应用模板

XSLT: Replace only certain subnodes of an element in a template, apply-templates on the other

我必须将一个 XML 转换成另一个 XML,目前我遇到了一个小问题: 在我的 XSLT 中,我匹配了一个项目并替换了它的一些子元素,我希望将其余部分替换为 apply-template.

示例:

有了这个输入:

<?xml version="1.0" encoding="utf-8"?>
<ConfigurationNodes>
   <Versions>
      <PackagesA Version="1.8" />
      <PackageB Version="1.1" />
      <PackageC Version="1.7" />
   </Versions>
   <ConfigurationNode  Type="SomeSpecialType">
      <Name>MyName</Name>
      <Revision>0</Revision>
      <Description >The big full description here</Description>
      <Status Type="SpecialType2">
        <Value>Normal</Value>
        <Severity>255</Severity>
      </Status>
   </ConfigurationNode>
</ConfigurationNodes>

我想以此结束:

<?xml version="1.0" encoding="utf-8"?>
<ConfigurationNodes>
   <Versions>
      <PackagesA Version="1.8" />
      <PackageB Version="1.1" />
      <PackageC Version="1.7" />
   </Versions>
   <Object Name="Configuration" NodeType="SomeOtherType">
      <Property Name="Name" Value="MyName" Type="System.String" />
      <Property Name="Description" Value="The big full description here" Type="System.String" />
      <Property Name="Revision" Value="0" Type="System.Int32" />
      <Object Name="Status" Type="SomeOtherSpecialType2">
         <Property Name="Value" Value="Normal" Type="System.String" />
         <Property Name="Severity" Value="255" Type="System.Int32" />
      </Object>
   </Object>
</ConfigurationNodes>

目前我有这个 XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="*[@Type='SomeSpecialType']">
    <Object Name="Configuration" NodeType="SomeOtherType">
      <Property Name="Name" Value="{Name/text()}" Type="System.String"/>
      <Property Name="Description" Value="{Description/text()}" Type="System.String"/>
      <Property Name="Revision" Value="{Revision/text()}" Type="System.Int32" />
      <xsl:apply-templates select="Status"/>
    </Object>
  </xsl:template>

  <xsl:template match="*[@Type='SpecialType2']">
    <Object Name="Status" Type="SomeOtherSpecialType2">
      <Property Name="Value" Value="Normal" Type="System.String"  />
      <Property Name="Severity" Value="255" Type="System.Int32"  />
    </Object>
  </xsl:template>

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

哪个returns我:

<?xml version="1.0" encoding="utf-8"?>
<ConfigurationNodes>
   <Versions>
      <PackagesA Version="1.8" />
      <PackageB Version="1.1" />
      <PackageC Version="1.7" />
   </Versions>
   <Object Name="Configuration" NodeType="SomeOtherType">
   <Property Name="Name" Value="MyName" Type="System.String" />
   <Property Name="Description" Value="The big full description here" Type="System.String" />
   <Property Name="Revision" Value="0" Type="System.Int32" />
   <Name>MyName</Name>
   <Revision>0</Revision>
   <Description>The big full description here</Description>
   <Object Name="Status" Type="SomeOtherSpecialType2">
      <Property Name="Value" Value="Normal" Type="System.String" />
      <Property Name="Severity" Value="255" Type="System.Int32" /></Object>
   </Object>
</ConfigurationNodes>

所以第一个模板中使用的元素仍然被复制(我猜是因为它们不匹配)。

我也知道我可以输入 <xsl:apply-templates select="Status"/>,这会给我预期的结果,但在我未来的实际情况下,我希望所有不匹配的子元素都根据它们的类型检查另一个模板。

可不可以?

尝试制作您的第一个模板:

<xsl:template match="*[@Type='SomeSpecialType']">
    <Object Name="Configuration" NodeType="SomeOtherType">
        <Property Name="Name" Value="{Name}" Type="System.String"/>
        <Property Name="Description" Value="{Description}" Type="System.String"/>
        <Property Name="Revision" Value="{Revision}" Type="System.Int32" />
        <xsl:apply-templates select="*[not(self::Name or self::Description or self::Revision)]"/>
    </Object>
</xsl:template>

这会将模板应用到当前元素的所有子元素,但您已经明确用于填充属性的子元素除外。


编辑:

I was more looking to a way where I don't have to specify all the elements

那我建议你这样试试:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="*[@Type='SomeSpecialType']">
    <Object Name="Configuration" NodeType="SomeOtherType">
        <xsl:apply-templates/>
    </Object>
</xsl:template>

<xsl:template match="*[@Type='SpecialType2']">
    <Object Name="Status" Type="SomeOtherSpecialType2">
        <Property Name="Value" Value="Normal" Type="System.String"  />
        <Property Name="Severity" Value="255" Type="System.Int32"  />
    </Object>
</xsl:template>

<xsl:template match="Name | Description">
    <Property Name="{name()}" Value="{.}" Type="System.String"/>
</xsl:template>

<xsl:template match="Revision">
    <Property Name="Revision" Value="{.}" Type="System.Int32"/>
</xsl:template>

</xsl:stylesheet>