模式不输出预期节点数据的命名模板

Posted

技术标签:

【中文标题】模式不输出预期节点数据的命名模板【英文标题】:Named template with mode not outputting expected node data 【发布时间】:2021-11-20 23:18:57 【问题描述】:

我有以下输入、转换和输出 XML。输出 XML 不是我所期望的。我试图在我的模板中使用 mode 属性将我的处理分为两个步骤。 Step1 过滤输入 XML,Step2 处理我希望过滤的输入 XML 中的特定节点。我的 Step2 模板只是输出他们收到的内容,因此我希望看到为每个模板选择的节点的完整描述。输出 XML 仅包含***节点标签(Patient、Encounters、Diagnoses)和节点本身的文本。

我在My XSLT fiddle 有以下 XSLT 小提琴,它显示了我的问题,我希望清楚。

输入 XML

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <Container>
    <Patient>
      <BirthTime>2001-01-01T00:00:00Z</BirthTime>
    </Patient>
    <Encounters>
      <Encounter>
        <EncounterNumber>1</EncounterNumber>
        <FromTime>2021-04-01T00:00:00Z</FromTime>
      </Encounter>
      <Encounter>
        <EncounterNumber>2</EncounterNumber>
        <FromTime>2021-03-01T00:00:00Z</FromTime>
      </Encounter>
    </Encounters>
    <Diagnoses>
      <Diagnosis>
        <EncounterNumber>1</EncounterNumber>
      </Diagnosis>
      <Diagnosis>
        <EncounterNumber>2</EncounterNumber>
      </Diagnosis>
    </Diagnoses>
  </Container>
</root>

转换 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"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:variable name="encounterNumbers">
    <EncounterNumber>2</EncounterNumber>
  </xsl:variable>

  <!-- START PROCESSING -->
  <xsl:template match="node()|@*">
    <xsl:apply-templates select="." mode="step1"/>
  </xsl:template>

  <!-- STEP1 TEMPLATES -->
  <xsl:template name="filterSDA" mode="step1" match="node()|@*">
    <xsl:variable name="filteredSDA">
      <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
      </xsl:copy>
    </xsl:variable>

    <xsl:apply-templates select="$filteredSDA" mode="step2"/>

  </xsl:template>
  
  <xsl:template match="//Encounters/Encounter[not(EncounterNumber = $encounterNumbers/EncounterNumber)]" mode="step1"/>
  <xsl:template match="//Diagnoses/Diagnosis[not(EncounterNumber = $encounterNumbers/EncounterNumber)]"  mode="step1"/>

  <!-- STEP2 TEMPLATES -->
  <xsl:template name="demographics" mode="step2" match="Patient">

    <xsl:copy-of select="." />
  </xsl:template>

  <xsl:template name="clinical" mode="step2" match="Encounters|Diagnoses">

    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

输出 XML

<?xml version="1.0" encoding="UTF-8"?>
<Patient>
      2001-01-01T00:00:00Z
    </Patient>
<Encounters>
      
      
        2
        2021-03-01T00:00:00Z
      
      
    </Encounters>
<Diagnoses>
      
      
        2
      
    </Diagnoses>

【问题讨论】:

命名模板需要由xsl:call-template 调用,如果name 应该有任何意义。模式通常与xsl:apply-templates 一起使用,而不是与xsl:call-template 一起使用。目前尚不清楚您的第一步是要处理和创建什么作为中间结果,第二步应该如何处理中间结果以及最终结果的外观。因此,也许可以通过口头描述和 XML 样本来解释这一点。 如果我只添加以下两个 xsl 语句,我的原始小提琴按预期工作: 【参考方案1】:

我认为您通过将命名模板(您似乎无处调用)与匹配模板混合使事情变得过于复杂。

此外,如果您想要具有两种不同模式的两阶段处理,我会在顶层执行此操作,将通过第一种模式处理整个输入的结果推送到一个变量中,然后在该变量上应用第二种模式:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:variable name="encounterNumbers">
    <EncounterNumber>2</EncounterNumber>
    <EncounterNumber>3</EncounterNumber>
    <EncounterNumber>4</EncounterNumber>
  </xsl:variable>
  
  <xsl:mode name="step1" on-no-match="shallow-copy"/>
  
  <xsl:mode name="step2" on-no-match="shallow-copy"/>

  <!-- START PROCESSING -->
  <xsl:template match="/">
    <xsl:variable name="step-1-result">
      <xsl:apply-templates mode="step1"/>
    </xsl:variable>
    <xsl:apply-templates select="$step-1-result/node()" mode="step2"/>
  </xsl:template>
  
  <!-- mode step1 templates -->
  <xsl:template match="//Encounters/Encounter[not(EncounterNumber = $encounterNumbers/EncounterNumber)]" mode="step1"/>
  <xsl:template match="//Diagnoses/Diagnosis[not(EncounterNumber = $encounterNumbers/EncounterNumber)]"  mode="step1"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/asoTKZ/20

【讨论】:

马丁 - 感谢您的评论。使用上面的结构现在可以工作了!再次感谢! Martin - 我不明白的一个问题。我在您的小提琴中添加了以下“step2”模板: 我现在将 Demographics 节点嵌入到 Container 节点中。如何只输出 Demographics 节点?

以上是关于模式不输出预期节点数据的命名模板的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WinForms 中禁用 TreeView 的节点重命名?

如何重命名运行 mnesia 数据库的节点

空操作命名空间

循环模式给出错误为“错误:模式必须包含唯一的命名类型,但包含多个名为“节点”的类型。”

在可视化映射器中将命名空间添加到根节点

XSLT3 未命名的 xsl:mode on-no-match 行为是不是应该应用于没有模式匹配但模式在应用模板上指定的元素?