用于创建缺失元素的 XSLT 模板

XSLT templates for creating missing elements confict with each other

提问人:deuri 提问时间:3/27/2021 最后编辑:Thomas Hansendeuri 更新时间:3/31/2021 访问量:92

问:

我使用 XSLT 转换来添加元素和 XML 数据,以防缺少一个或两个元素。我想使用独立的模板来处理其中的每一个,但似乎只有一个模板生效。configurationstatus

源数据:

<data>
  <environment>
    <id>test</id>
    <details>Detail info for environment...</details>
  </environment>
  <default_conf>abcd1234</default_conf>
  <default_status>1</default_status>
</data>

XSLT的:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />
    <!-- identity transformation -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
 <!-- if configuration not given, create it with the value of default_conf -->
 <xsl:template match="data[not(configuration)]">
   <xsl:copy>
     <xsl:apply-templates/>
        <!--xsl:apply-templates select="@*|node()"/-->
       <configuration><xsl:value-of select="default_conf"/></configuration>
   </xsl:copy>
 </xsl:template>
 <!-- if status not given, create it with the value of default_status -->
 <xsl:template match="data[not(status)]">
   <xsl:copy>
     <xsl:apply-templates/>
     <!--xsl:apply-templates select="@*|node()"/-->
     <status><xsl:value-of select="default_status"/></status>
   </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在结果 XML 中,仅创建元素,而不创建元素。转换模板有什么问题以及如何纠正它?

请注意,我还需要传递 and 元素,因此我不想重命名这些元素。default_confdefault status

期望输出:

<data>
  <environment>
    <id>test</id>
    <details>Detail info for environment...</details>
  </environment>
  <default_conf>abcd1234</default_conf>
  <default_status>1</default_status>
  <configuration>abcd1234</configuration>
  <status>1</status>
</data>
XML XSLT

评论

0赞 Martin Honnen 3/27/2021
使用匹配同一元素的两个不同模板很难处理这个问题,除非您运行两个转换步骤,例如将第一个元素添加的结果存储在变量中,然后将其推送到另一个处理中。这在 XSLT 2 或更高版本中相当容易,但在 XSLT 1 中,任何变量都是结果树片段,您需要使用或类似才能将其转换为节点集。作为替代方案,您可以考虑添加检查,例如 同样,对于单个模板中的其他元素。exsl:node-set<xsl:if test="not(status)"><status>...</status></xsl:if>

答:

1赞 michael.hor257k 3/27/2021 #1

在 XSLT 中,

通过查找具有与节点匹配的模式的所有模板规则,并从中选择最佳规则来处理节点;
https://www.w3.org/TR/1999/REC-xslt-19991116/#section-Processing-Model

如果两者都缺少 and,则有两个模板与同一节点匹配,具有相同的优先级。这是一个错误:configurationstatus

XSLT 处理器可能会发出错误信号;如果它没有发出错误的信号,则必须通过从剩余的匹配模板规则中选择样式表中最后出现的规则来恢复。
https://www.w3.org/TR/1999/REC-xslt-19991116/#conflict

简单的解决方案是使用带有两条指令的单个模板来添加每个缺失的节点。否则,您需要使用的不是两个,而是三个模板 - 并确保添加的模板优先。xsl:if

评论

0赞 deuri 3/27/2021
感谢 michael.hor257k,它帮助我将解决方案设计为单个模板,每个可选元素都有一个 if 语句。