【问题标题】:xpath to see if "current node" exists in external file nodeset attributexpath 查看外部文件节点集属性中是否存在“当前节点”
【发布时间】:2018-11-27 08:19:30
【问题描述】:

背景 我有一个 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,运气不好,我一直在寻找,但无济于事。

问题在于它总是呈现为真,即使使用不在代码列表中的 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 文档中使用,这就是它具有这种结构的原因。我想如果我重复使用它,它的维护就更少了。

【问题讨论】:

  • 我认为你想比较 g[contains(@name, current()] 而不是 g[contains(@name,.)]。您尝试中的点 . 指的是您放置谓词的 g 元素。
  • 谢谢!您是对的,但是,即使有效属性值列表中不存在该值,验证仍然会进行。 xpath 表达式中是否存在一些我没有发现的明显逻辑错误?
  • 恐怕我还没有理解应该进行的那种验证,不清楚。尝试将问题减少到最小但完整的 XSLT 和 XML 示例以及想要的输出和当前输出,以允许其他人重现该问题。鉴于至少您的一些 XML 示例使用各种名称空间,因此根本不清楚您的 XSLT 匹配模式匹配什么以及您的 XPath 表达式选择什么,而没有看到任何带有名称空间声明(和xpath-default-namespace 声明?)的完整 XSLT 示例。

标签: xml xslt schematron


【解决方案1】:

由于这是一个 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,.)] 中使用. 时,上下文是&lt;g&gt; 元素,因此您将元素的字符串值与其属性之一的值进行比较。尝试在谓词中使用原始上下文中的某些内容时,通常要做的事情是声明并使用变量作为您要使用的值。在 Schematron 中,您将使用 &lt;let&gt; 元素。

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

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

修改后的 XSLT 是:

<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>

【讨论】:

  • 感谢您就此事提供非常有用的意见并进一步解释 schematron 的工作原理!我将更新我如何解决它的评论。
【解决方案2】:

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

但是,我发现在 schematron 文件的上层已经有一个相同 xml 节点的规则。我最终添加了另一个 &lt;assert&gt; 并且它起作用了(以及其他一些更改)。

这就是它现在在 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

再次感谢您的有用补充和有用的 cmets。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    • 2023-04-03
    相关资源
    最近更新 更多