0

我已经用 XSLT 训练自己大约 1.5 个月了。我已经制作了一个简化的较短版本,我无法弄清楚,并且非常感谢任何帮助,因为我被困在这个问题上。谢谢!

基本情况:

根属性中有一个字符串,其祖先元素定义为 xpath:

/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:definition/v3:valueSet/v3:id/@root

...当与带有元素条目祖先的 valueSet 属性的 id 匹配时,xpath:

/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:entry/v3:observationCriteria/v3:value/@valueSet

或者

/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:entry/v3:observationCriteria/v3:code/@valueSet

输出(需要并且当前确实)显示字符串及其必需的属性。

但是,当这些位置中的字符串不匹配时,还必须列出该字符串,并带有“未指定”标题。

错误: 即使所有现有字符串都匹配,也会列出“未指定”标头及其字符串。在这种情况下,应该只列出匹配的字符串。

问题翻译器(XSL 文件):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xalan="http://xml.apache.org/xalan"
  xmlns:v3="urn:hl7-org:v3"
  xmlns:rvs="urn:ihe:iti:svs:2008">  
  <xsl:output method="html" standalone="yes" omit-xml-declaration="no" indent="yes" xalan:indent-amount="2"/>    

  <xsl:template 
    match="/v3:QualityMeasureDocument">
    <html>
      <head>
        <title>Test 'I'</title>
      </head>
      <body>
        <ul>
          <xsl:apply-templates select="//v3:dataCriteriaSection" />
        </ul>
      </body>
    </html>  
  </xsl:template>

  <xsl:template
    match="v3:dataCriteriaSection">    
    <xsl:for-each select="//v3:entry">      
      <xsl:if test="*/v3:value/@valueSet">                    
        <xsl:call-template name="definitionValueSet">
          <xsl:with-param name="cur_valueSetID" select="*/v3:value/@valueSet"/> 
        </xsl:call-template>        
      </xsl:if>      
      <xsl:if test="*/v3:code/@valueSet">               
        <xsl:call-template name="definitionValueSet">
          <xsl:with-param name="cur_valueSetID" select="*/v3:code/@valueSet"/> 
        </xsl:call-template>        
      </xsl:if>      
      <xsl:if test="*/v3:participant/v3:roleParticipant/v3:code/@valueSet">                     
        <xsl:call-template name="definitionValueSet">
          <xsl:with-param name="cur_valueSetID" select="*/v3:participant/v3:roleParticipant/v3:code/@valueSet"/> 
        </xsl:call-template>        
      </xsl:if>                  
    </xsl:for-each>                
  </xsl:template>

  <xsl:template
    name="definitionValueSet">  
    <xsl:param name="cur_valueSetID"/>                     
    <xsl:for-each select="//v3:valueSet">                                
      <xsl:choose>    
        <xsl:when test="$cur_valueSetID != v3:id/@root or
        not( v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)] ) or
        not( v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID )">   
          <xsl:if test="not($cur_valueSetID = '')">                                                    
            <li>
            <xsl:text>Not Specified</xsl:text>                                     
              <ul>
                <li>                       
                <xsl:text>ValueSet: </xsl:text>
                <xsl:value-of select="$cur_valueSetID"></xsl:value-of> 
                </li>
              </ul>
            </li>                 
          </xsl:if>
        </xsl:when>
        <xsl:when test="v3:id/@root = $cur_valueSetID"> 
          <xsl:if test="v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)]">
            <xsl:if test="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID">                 
              <li>       
                <xsl:text>Id: </xsl:text>
                <xsl:value-of select="v3:id/@root"/>                               
                <xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
                  <ul>
                    <li>
                      <xsl:if test="not(@code = '')">
                        <xsl:if test="@code">
                          <xsl:text>code = </xsl:text>
                          <xsl:value-of select="@code"></xsl:value-of>
                          <xsl:text> </xsl:text>
                        </xsl:if>
                      </xsl:if>
                    </li>
                  </ul>        
                </xsl:for-each>
              </li>
            </xsl:if>
          </xsl:if>
        </xsl:when>    
      </xsl:choose>    
    </xsl:for-each>
  </xsl:template>                      
</xsl:stylesheet>

XML 输入文件 'I' xml:

<?xml version="1.0" encoding="UTF-8"?>
<QualityMeasureDocument xmlns="urn:hl7-org:v3">
  <component>
    <dataCriteriaSection>
      <definition>
        <valueSet>
          <!-- Value Set for Race -->
          <id root='1.1.1.1.1.1.1' />
          <text>
            <reference
              value='https://localhost/RetrieveValueSet?id=1.1.1.1.1.1.1' />
            <RetrieveValueSetResponse xmlns="urn:ihe:iti:svs:2008">
              <ValueSet id="1.1.1.1.1.1.1">
                <ConceptList>
                  <Concept code="4" />
                  <Concept code="5" />
                  <Concept code="6" />
                </ConceptList>
              </ValueSet>
            </RetrieveValueSetResponse>
          </text>
        </valueSet>
      </definition>
      <definition>
        <valueSet>
          <id root='1.1.1.1.1.1.2' />
          <text>
            <reference
              value='https://localhost/RetrieveValueSet?id=1.1.1.1.1.1.2' />
            <RetrieveValueSetResponse xmlns="urn:ihe:iti:svs:2008">
              <ValueSet id="1.1.1.1.1.1.2">
                <ConceptList>
                  <Concept code="007.2" />
                  <Concept code="007.3" />
                </ConceptList>
              </ValueSet>
            </RetrieveValueSetResponse>
          </text>
        </valueSet>
      </definition>
      <entry>
        <observationCriteria>
          <code code="424144002" codeSystem="123123213"
            displayName="FEWFW" />
          <value>
            <low />
            <high />
          </value>
        </observationCriteria>
      </entry>
      <entry>
        <observationCriteria>
          <code code="DFHKJ" codeSystem="ASKJDHK" displayName="ASDNJK" />
          <value>
            <width />
          </value>
        </observationCriteria>
      </entry>
      <entry>
        <observationCriteria>
          <code code="FDSFD" codeSystem="JHBHJB" displayName="HJGJH" />
          <value valueSet="1.1.1.1.1.1.1" />
        </observationCriteria>
      </entry>
      <entry>
        <encounterCriteria>
          <code valueSet="1.1.1.1.1.1.2" />
        </encounterCriteria>
      </entry>
    </dataCriteriaSection>
  </component>
</QualityMeasureDocument>

预期的输出代码“I”HTML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html xmlns:xalan="http://xml.apache.org/xalan" xmlns:rvs="urn:ihe:iti:svs:2008" xmlns:v3="urn:hl7-org:v3">
  <head>
    <title>Test 'I'</title>
  </head>
  <body>
    <ul>
      <li>Id: 1.1.1.1.1.1.1
        <ul>
          <li>code = 4 </li>
        </ul>
        <ul>
          <li>code = 5 </li>
        </ul>
        <ul>
          <li>code = 6 </li>
        </ul>
      </li>
      <li>Id: 1.1.1.1.1.1.2
        <ul>
          <li>code = 007.2 </li>
        </ul>
        <ul>
          <li>code = 007.3 </li>
        </ul>
      </li>
    </ul>
  </body>
</html>

通过 hack 或只是擦除代码来创建正确的输出很简单,但这需要在所有情况下都有效。例如,根本没有匹配项并且每次出现时只显示“未指定”标头及其字符串,或者两种情况的混合。该代码当前在没有匹配项的情况下工作,并在每次出现时显示“未指定”标题及其字符串。

似乎如果可以做到这一点,“如果它不匹配并且尚未列出”,它将解决问题。

希望有帮助。如果您想了解更多信息或更多文件,请告诉我。任何提示都会很棒!谢谢。

4

2 回答 2

0

我认为您遇到的主要问题是在您的命名模板“definitionValueSet”中,您在其中使用xsl:for-each遍历 valueSet元素

<xsl:for-each select="//v3:valueSet"> 

在此测试相关属性是否与当前参数匹配,如果找到匹配项,则输出列表。但是所有valueSet元素都会被搜索,所以即使一个匹配,你仍然会处理那些不匹配的元素,所以你的xsl:if也会被调用。这导致输出“未指定”。

您真正需要做的是仅匹配valueSet元素(如果存在),如果不存在匹配的元素,则输出您的“未指定”。

一种方法是首先创建一个变量来保存匹配的valueSet元素的唯一 id

<xsl:variable name="valueSet">
   <xsl:value-of select="generate-id(//v3:valueSet[v3:id/@root = $cur_valueSetID and v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)] and v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID])"/>
</xsl:variable>

然后,您可以测试是否已设置,如果已设置,则为该元素应用模板。如果未设置,您可以使用未指定的代码

<xsl:choose>
   <xsl:when test="$valueSet">
      <xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>
   </xsl:when>
   <xsl:otherwise>
      <!-- Not Specified -->
   </xsl:otherwise>
</xsl:choose>

这是完整的 XSLT,它有望提供您需要的输出

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan" xmlns:v3="urn:hl7-org:v3" xmlns:rvs="urn:ihe:iti:svs:2008">
   <xsl:output method="html" standalone="yes" omit-xml-declaration="no" indent="yes" xalan:indent-amount="2"/>
   <xsl:template match="/v3:QualityMeasureDocument">
      <html>
         <head>
            <title>Test 'I'</title>
         </head>
         <body>
            <ul>
               <xsl:apply-templates select="//v3:dataCriteriaSection"/>
            </ul>
         </body>
      </html>
   </xsl:template>
   <xsl:template match="v3:dataCriteriaSection">
      <xsl:for-each select=".//v3:entry">
         <xsl:if test="*/v3:value/@valueSet">
            <xsl:call-template name="definitionValueSet">
               <xsl:with-param name="cur_valueSetID" select="*/v3:value/@valueSet"/>
            </xsl:call-template>
         </xsl:if>
         <xsl:if test="*/v3:code/@valueSet">
            <xsl:call-template name="definitionValueSet">
               <xsl:with-param name="cur_valueSetID" select="*/v3:code/@valueSet"/>
            </xsl:call-template>
         </xsl:if>
         <xsl:if test="*/v3:participant/v3:roleParticipant/v3:code/@valueSet">
            <xsl:call-template name="definitionValueSet">
               <xsl:with-param name="cur_valueSetID" select="*/v3:participant/v3:roleParticipant/v3:code/@valueSet"/>
            </xsl:call-template>
         </xsl:if>
      </xsl:for-each>
   </xsl:template>

   <xsl:template name="definitionValueSet">
      <xsl:param name="cur_valueSetID"/>
      <xsl:variable name="valueSet">
         <xsl:value-of select="generate-id(//v3:valueSet[v3:id/@root = $cur_valueSetID and v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)] and v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID])"/>
      </xsl:variable>
      <xsl:choose>
         <xsl:when test="$valueSet != ''">
            <xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>
         </xsl:when>
         <xsl:otherwise>
            <li>
               <xsl:text>Not Specified</xsl:text>
               <ul>
                  <li>
                     <xsl:text>ValueSet: </xsl:text>
                     <xsl:value-of select="$cur_valueSetID"/>
                  </li>
               </ul>
            </li>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="v3:valueSet">
      <li>
         <xsl:text>Id: </xsl:text>
         <xsl:value-of select="v3:id/@root"/>
         <xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
            <ul>
               <li>
                  <xsl:if test="not(@code = '')">
                     <xsl:if test="@code">
                        <xsl:text>code = </xsl:text>
                        <xsl:value-of select="@code"/>
                        <xsl:text/>
                     </xsl:if>
                  </xsl:if>
               </li>
            </ul>
         </xsl:for-each>
      </li>
   </xsl:template>
</xsl:stylesheet>

请注意,如评论中所述,小心使用 expression //v3:entry。这是一个绝对表达式,将匹配文档中的任何元素(即从根元素向下搜索)。如果您只想查看当前元素,请使用相对表达式.//v3:entry

编辑:对于这方面的轻微变体,作为查找valueSet元素的一种可能更有效的方法,您可以在 XSLT 文档的顶部定义一个键

<xsl:key name="valueSet" match="v3:valueSet" use="generate-id()" />

然后,而不是这样做来查找正确的valueSet元素

<xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>

您可以改用密钥

<xsl:apply-templates select="key('valueSet', $valueSet)"/> 
于 2012-08-24T15:23:33.957 回答
0

以下是为理解而提供的简单替代解决方案(不使用 generate-id() 或 key() )。它的效率可能不如 Tim C 的出色答案,也不应取代 Tim C 的出色答案。我只是提供这个让人们可以学习,并表明我全力以赴解决这个问题,而不是仅仅得到我需要的东西并继续前进。

解决方案是对原始“问题翻译器”的修复。唯一需要从该 XSL 文件中编辑(尽管很繁重)的部分是名为“definitionValueSet”的模板。

首先,我们需要创建一个变量$valueSetData ,它一次性存储v3:id/@root的所有值,它们之间有一个“,”,以便以后单独引用。它就像一个新的临时数据库。
for-each 包含一个根据要求限制匹配的谓词。这些包含在声明中,因为它们是那里的本地节点。此外,这可以避免以后处理额外的条件检查。

<xsl:variable name="valueSetData">
   <xsl:for-each select="//v3:valueSet[
                           v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)] and 
                           v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID]">       
     <xsl:value-of select="v3:id/@root"/>
     <xsl:text>,</xsl:text>
   </xsl:for-each>
</xsl:variable>

接下来我们有选择语句,针对具体情况进行了编辑。该语句确定是否与$valueSetData “数据库”中的$ cur_valueSetID匹配。for-each 谓词限制重复匹配(由于上下文而具有错误值)。

    <xsl:choose>    
      <xsl:when test="contains($valueSetData, $cur_valueSetID)"> 
        <xsl:for-each select="//v3:valueSet[$cur_valueSetID = v3:id/@root]">
          <!-- Display found matches which meet all requirements -->
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <!-- Display Not Specified -->
      </xsl:otherwise>                                                                            
    </xsl:choose>   

完整的“definitionValueSet”模板:

  <xsl:template
    name="definitionValueSet">  
    <xsl:param name="cur_valueSetID"/>  
    <xsl:variable name="valueSetData">
       <xsl:for-each select="//v3:valueSet[
                               v3:text/v3:reference[starts-with(@value, 'https://') and contains(@value, $cur_valueSetID)] and 
                               v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/@id = $cur_valueSetID]">       
         <xsl:value-of select="v3:id/@root"/>
         <xsl:text>,</xsl:text>
       </xsl:for-each>
    </xsl:variable>                                     
    <xsl:choose>    
      <xsl:when test="contains($valueSetData, $cur_valueSetID)"> 
        <xsl:for-each select="//v3:valueSet[$cur_valueSetID = v3:id/@root]">
          <li>       
            <xsl:text>Id: </xsl:text>
            <xsl:value-of select="v3:id/@root"/>                               
            <xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
              <ul>
                <li>
                  <xsl:if test="not(@code = '')">
                    <xsl:if test="@code">
                      <xsl:text>code = </xsl:text>
                      <xsl:value-of select="@code"></xsl:value-of>
                      <xsl:text/>
                    </xsl:if>
                  </xsl:if>
                </li>
              </ul>        
            </xsl:for-each>
          </li>            
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <li>
          <xsl:text>Not Specified</xsl:text>                                     
          <ul>
            <li>                       
              <xsl:text>ValueSet: </xsl:text>
              <xsl:value-of select="$cur_valueSetID"></xsl:value-of> 
            </li>
          </ul>
        </li> 
      </xsl:otherwise>                                                                            
    </xsl:choose>   
  </xsl:template>
于 2012-08-27T21:40:23.577 回答