xpath查看外部文件nodeset属性中是否存在"current node"

xpath to see if "current node" exists in external file nodeset attribute

背景 我有一个 schematron 验证和 xslt 到 pdf 的翻译。

问题 我想检查 xml 标签中的内容是否存在于外部文件的有效代码列表中。只有外部文件中的属性值是有趣的。节点值在另一个样式表中用于其他目的。

<xsl:template match="//medicalFieldcode" priority="1000" mode="M4">
    <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" context="//medicalFieldcode"/>
    <xsl:variable name="MVOcodes" select="document('verksamhetskodlista.xml')"/>

    <!--ASSERT -->
    <xsl:choose>

        <xsl:when test="boolean($MVOcodes/module/document-merge/g-funcs/g[contains(@name,.)])"/>

        <xsl:otherwise>
            <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                            test="boolean($MVOcodes/module/document-merge/g-funcs/g[contains(@name,.)])">
                <xsl:attribute name="id">R43</xsl:attribute>
                <xsl:attribute name="location">
                    <xsl:apply-templates select="." mode="schematron-select-full-path"/>
                </xsl:attribute>
                <svrl:text>MedicalFieldCode must be in the valid list of codes.</svrl:text>
            </svrl:failed-assert>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M4"/>
</xsl:template>

外部文件(verksamhetskodlista.xml)具有以下结构:

<module xmlns:mmx="http://funx" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:fnc="http://funx/fnc" xmlns:att="http://funx/att" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<document-merge>
    <g-funcs>
        <g name="003">value1</g>
        <g name="009">another value</g>
        <g name="011">yet another value</g>
        <!-- ... -->
    </g-funcs>
</document-merge>

从示例中提取 xml:

<ProcessClaimSpecification xmlns="urn:riv:financial:billing:claim:ProcessClaimSpecificationResponder:1">
<s01:claimSpecification xmlns="urn:riv:financial:billing:claim:1" xmlns:s01="urn:riv:financial:billing:claim:ProcessClaimSpecificationResponder:1">
    <healthCareServicesSpecificationLine>
        <healthcarePerformed>
            <!-- a bunch of content --> 
            <activity>
                <medicalFieldCode>000</medicalFieldCode>
            </activity>
        </healthcarePerformed>
    </healthCareServicesSpecificationLine>
</s01:claimSpecification>

我需要使用 xpath 对此进行验证。 我试过应用这个 contains instruction w/o 运气,我一直在搜索但无济于事。

问题是它总是呈现为真,即使使用不在代码列表中的 000 也是如此。 我已经尝试了 xpath 包含的许多不同的重组变体,但它的工作效果并不令人满意。我不确定从正确的角度来这里。我使用的是 xslt 2.0,所以变量应该包含一个节点集。

除其他外,我已经尝试过这些 xpath 表达式

boolean($MVOcodes/module/document-merge/g-funcs/g[contains(@name,.)])
contains($MVOcodes/module/document-merge/g-funcs/g/@name, .)

我已经处理了好几天了,没有任何进展所以请帮忙? 外部文件也在另一个 xsl 文档中使用,这就是它具有这种结构的原因。我想如果我重用它,维护起来就更少了。

由于这是一个 Schematron 问题,如果您发布了 Schematron,而不是从 Schematron 生成的 XSLT,可能会更清楚。事实上,我使用了您的 XSLT,我会留给您修改您的 Schematron 以同样的方式工作。

首先,您当前的 XSLT 匹配 medicalFieldcode,而不是 medicalFieldCode。请注意 cC.

其次,您可能需要在 XPath 中为您的上下文元素命名空间。在下面的示例中,我为 urn:riv:financial:billing:claim:1 命名空间 URI 使用 claim 前缀。

第三,XPath 中的 . 表示当前上下文(参见 https://www.w3.org/TR/2010/REC-xpath20-20101214/#doc-xpath-ContextItemExpr)。因此,当您在 g[contains(@name,.)] 中使用 . 时,上下文是 <g> 元素,因此您将元素的字符串值与其属性之一的值进行比较。尝试在谓词中使用原始上下文中的内容时,通常要做的是声明一个变量并将其用于您要使用的值。在 Schematron 中,您将使用 <let> 元素。

第四,exists() 是一种有用的 XPath 2.0(及更高版本)方法,用于查看 XPath 是否匹配任何内容。即,如果 XPath 的计算结果不是空序列(请参阅 https://www.w3.org/TR/xquery-operators/#func-exists)。

最后,是的,重用现有数据文件几乎肯定是个好主意,而不是必须以两种不同的方式维护相同的数据。

最终修改后的 XSLT,我将留给您转回 Schematron,是:

<xsl:template match="//claim:medicalFieldCode" priority="1000">
    <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" context="//medicalFieldcode"/>
    <xsl:variable name="MVOcodes" select="document('verksamhetskodlista.xml')"/>
    <xsl:variable name="code" select="." />

    <!--ASSERT -->
    <xsl:choose>

        <xsl:when test="exists($MVOcodes/module/document-merge/g-funcs/g[@name eq $code])"/>

        <xsl:otherwise>
            <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                            test="exists($MVOcodes/module/document-merge/g-funcs/g[contains(@name,.)])">
                <xsl:attribute name="id">R43</xsl:attribute>
                <xsl:attribute name="location">
                    <xsl:apply-templates select="." mode="schematron-select-full-path"/>
                </xsl:attribute>
                <svrl:text>MedicalFieldCode must be in the valid list of codes.</svrl:text>
            </svrl:failed-assert>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M4"/>
</xsl:template>

正如 Tony Graham 指出的那样,Xpath 可能会简化使用 exists。 type:o 也是我忽略的地方。上下文 xpath 中缺少命名空间也是如此。感谢您指出这些事情!

但是,我发现在 schematron 文件中已经有相同 xml 节点的规则。我最后添加了另一个 <assert> 并且它起作用了(连同其他一些更改)。

这是现在在 schematron 文件中的样子:

<rule context="//urn2:activity/urn2:medicalFieldCode" flag="fatal">
    <assert id="R33" test="((count(../../urn2:diagnosis) = 0) and (count(../../urn2:treatment) = 0)) or not(starts-with(., '9'))">Diagnoser och åtgärder får ej förekomma när medicalFieldCode börjar med 9. Underlags-id: <value-of select="//urn1:claimSpecification/urn2:id"/></assert>
    <assert id="R43" test="boolean(document('verksamhetskodlista.xml')/module/document-merge/g-funcs/g[contains(@name, current()/text())])" flag="fatal">MedicalFieldCode must be in the valid list of codes.</assert>
</rule>

这使得它成为已编译的 XSLT:

<xsl:template match="//urn2:activity/urn2:medicalFieldCode" priority="1007" mode="M3">
  <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                   context="//urn2:activity/urn2:medicalFieldCode"/>

        <!--ASSERT -->
<xsl:choose>
     <xsl:when test="((count(../../urn2:diagnosis) = 0) and (count(../../urn2:treatment) = 0)) or not(starts-with(., '9'))"/>
     <xsl:otherwise>
        <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                            test="((count(../../urn2:diagnosis) = 0) and (count(../../urn2:treatment) = 0)) or not(starts-with(., '9'))">
           <xsl:attribute name="id">R33</xsl:attribute>
           <xsl:attribute name="location">
              <xsl:apply-templates select="." mode="schematron-select-full-path"/>
           </xsl:attribute>
           <svrl:text>Diagnoser och åtgärder får ej förekomma när medicalFieldCode börjar med 9. Underlags-id: <xsl:text/>
              <xsl:value-of select="//urn1:claimSpecification/urn2:id"/>
              <xsl:text/>
           </svrl:text>
        </svrl:failed-assert>
     </xsl:otherwise>
  </xsl:choose>

        <!--ASSERT -->
<xsl:choose>
     <xsl:when test="boolean(document('verksamhetskodlista.xml')/module/document-merge/g-funcs/g[contains(@name, current()/text())])"/>
     <xsl:otherwise>
        <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                            test="boolean(document('verksamhetskodlista.xml')/module/document-merge/g-funcs/g[contains(@name, current()/text())])">
           <xsl:attribute name="id">R43</xsl:attribute>
           <xsl:attribute name="flag">fatal</xsl:attribute>
           <xsl:attribute name="location">
              <xsl:apply-templates select="." mode="schematron-select-full-path"/>
           </xsl:attribute>
           <svrl:text>MedicalFieldCode must be in the valid list of codes.</svrl:text>
        </svrl:failed-assert>
     </xsl:otherwise>
  </xsl:choose>
  <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3"/>
</xsl:template>

根据我的测试文件,这可以正常工作。

旨在失败的文件:

Result AnalyzeSchematronResult: MedicalFieldCode must be in the valid list of codes.

要成功的文件:

Passed OK Schematronvalidate

再次感谢您的有益补充和有益评论。