【问题标题】:Using Key Match to reference another node in XSLT 1.0在 XSLT 1.0 中使用键匹配来引用另一个节点
【发布时间】:2018-03-15 14:41:10
【问题描述】:

我希望将单个 XML 工作表与两个信息“部分”组合在一起,“Notes”和“Encounters”。每个笔记都有一个Extension ID,每个遭遇也有一个Extension ID

数据设置如下:

<Root>
  <Notes>
    <Note>
        <NoteText>
            <p>Text Paragraph 1</p>
            <p>Text Paragraph 2</p>
        </NoteText>
        <ExtensionID>123456</ExtensionID>
    </Note>
    <Note>
        <NoteText>
            <p>Text Paragraph 3</p>
        </NoteText>
        <ExtensionID>123456</ExtensionID>
    </Note>
    <Note>
        <NoteText>
            <p>Text Paragraph 4</p>
            <p>Text Paragraph 5</p>
        </NoteText>
        <ExtensionID>789012</ExtensionID>
    </Note>
  </Notes>
    <Encounter>
        <ExtensionID>123456</ExtensionID>
        <Date>2017-01-02</Date>
        <Author>Dr. George Smith</Author>
    </Encounter>
        <ExtensionID>798012</ExtensionID>
        <Date>2015-10-20</Date>
        <Author>Jenny Jones</Author>
    <Encounter>
<Root>

我想要以下输出:

<Import>
    <Notes>
        <Note ExtensionID="123456">
            <NoteText>
                <p>Text Paragraph 1</p>
                <p>Text Paragraph 2</p>
                <p>Text Paragraph 3</p>
            <NoteText>
            <Author>Dr. George Smith</Author>
            <Date>2015-10-20</Date>
        </Note>
        <Note ExtensionID="789012">
            <NoteText>
                <p>Text Paragraph 4</p>
                <p>Text Paragraph 5</p>
            <NoteText>
            <Author>Jenny Jones</Author>
            <Date>2015-10-20</Date>
        </Note>
    <Notes>
<Import>

我当前的 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="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">

      <Import>

      <Notes>
        <xsl:apply-templates select="Root/Notes"/>
      </Notes>
  </Import>
  </xsl:template>

  <xsl:key name ="ExtID" match="Note" use="ExtensionID"/>


  <xsl:template match="Root/Notes">
    <xsl:for-each select="Note[count(.|key('ExtID',ExtensionID)[1]) = 1]">
      <Note>
        <xsl:attribute name="ExtensionID">

          <xsl:value-of select="ExtensionID"/>

        </xsl:attribute>
        <xsl:for-each select="key('ExtID',ExtensionID)">
          <xsl:copy-of select="NoteText"/>
        </xsl:for-each>

      <xsl:for-each select="../../Encounters/Encounter[ExtensionID=key('ExtID',ExtensionID)]">
        <Author>
          <xsl:value-of select="Provider"/>        
        </Author>
        <Date>
            <xsl:value-of select="Date" />
        </Date>

      </xsl:for-each>
    </Note>
    </xsl:for-each>

  </xsl:template>
</xsl:stylesheet>

第一部分主要是按扩展 ID 分组的,但它是我正在努力处理的相关遭遇信息。

我注意到的是,它甚至没有进入带有“../../Encounters/Encounter[ExtensionID=key('ExtID',ExtensionID)]”的 for-each 循环。我几乎可以肯定我不能做我想做的事:像某种形式的“非变量”一样使用密钥,但我不确定接下来要尝试什么。

请注意:我受限于我们在办公室使用的软件,只能使用 XSLT 1.0。我无权访问 2.0 功能,也无法安装/升级或使用与 Visual Studio 中的引擎不同的引擎。

【问题讨论】:

  • 您的 XML 格式不正确(例如,您有一个开始的 &lt;Notes&gt; 标记,但没有结束标记)。此外,您的 XML 中的根元素是 Root,但在您的 XSLT 中您正在寻找 NoteRoot。由于 XML 格式不正确,因此不清楚这是您的问题中的拼写错误还是实际问题,因此您可能需要先更正您的 XML。谢谢!
  • 完全错字!谢谢你抓住它。这就是我过于简化的结果。

标签: xml xslt xslt-1.0


【解决方案1】:

这行确实有问题……

<xsl:for-each select="../../Encounters/Encounter[ExtensionID=key('ExtID',ExtensionID)]">

忽略您的 XML 中没有 Encounters 的事实,当您只需要当前 NoteExtensionID 的值时,“键”将返回一个 Note 节点。所以应该是这个....

<xsl:for-each select="../../Encounters/Encounter[ExtensionID=current()/ExtensionID]">

或者,如果您像这样定义另一个键...

<xsl:key name="EncID" match="Encounter" use="ExtensionID"/>

然后你可以这样做......

<xsl:for-each select="key('EncID', ExtensionID)">

试试这个 XSLT....

<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="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <Import>
      <Notes>
        <xsl:apply-templates select="Root/Notes"/>
      </Notes>
    </Import>
  </xsl:template>

  <xsl:key name ="ExtID" match="Note" use="ExtensionID"/>
  <xsl:key name="EncID" match="Encounter" use="ExtensionID"/>

  <xsl:template match="Notes">
    <xsl:for-each select="Note[count(.|key('ExtID',ExtensionID)[1]) = 1]">
      <Note ExtensionID="{ExtensionID}">
        <NoteText>
          <xsl:copy-of select="key('ExtID',ExtensionID)/NoteText/*"/>
        </NoteText>
        <xsl:for-each select="key('EncID', ExtensionID)">
          <Author>
            <xsl:value-of select="Author"/>        
          </Author>
          <Date>
           <xsl:value-of select="Date" />
          </Date>
        </xsl:for-each>
      </Note>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

也许您应该颠倒 XSLT 的逻辑?不要对Note 元素进行分组,而是先获取Encounter 元素,然后使用键获取它们的注释......

<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:key name="ExtID" match="Note" use="ExtensionID"/>

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

  <xsl:template match="/">
    <Import>
      <Notes>
        <xsl:apply-templates select="Root/Encounters/Encounter[key('ExtID', ExtensionID)]"/>
      </Notes>
    </Import>
  </xsl:template>

  <xsl:template match="Encounter">
    <Note ExtensionID="{ExtensionID}">
      <NoteText>
        <xsl:copy-of select="key('ExtID',ExtensionID)/NoteText/*"/>
      </NoteText>
      <xsl:apply-templates select="Author|Date" />
    </Note>
  </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 第一个建议效果很好!谢谢你快速的回复。我认为第二个选项将是一个很好的方法,但我将我的示例简化到它不会真正起作用的地步,我认为。您能解释一下 XSLT 如何“知道”匹配 Ext ID 和 EncID 吗?
  • 我不太清楚您的意思... ExtID 和 EncID 是键,您可以使用它们来选择与指定值匹配的节点。 XSLT 如何在幕后做到这一点,我不确定....
【解决方案2】:

为交叉引用定义第二个键:

<xsl:key name="ref" match="Encounter" use="ExtensionID"/>

然后你可以选择

  <xsl:for-each select="key('ref',ExtensionID)">
    <Author>
      <xsl:value-of select="Provider"/>        
    </Author>
    <Date>
        <xsl:value-of select="Date" />
    </Date>

  </xsl:for-each>

而不是

  <xsl:for-each select="../../Encounters/Encounter[ExtensionID=key('ExtID',ExtensionID)]">
    <Author>
      <xsl:value-of select="Provider"/>        
    </Author>
    <Date>
        <xsl:value-of select="Date" />
    </Date>

  </xsl:for-each>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    相关资源
    最近更新 更多