xpath以查看外部文件节点集属性

时间:2018-11-27 08:19:31

标签: xml xslt schematron

背景 我有一个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,它也始终呈现true。 我已经尝试过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文档中,这就是为什么它具有这种结构的原因。我认为如果重用它,维护起来就少了。

2 个答案:

答案 0 :(得分:0)

由于这是Schematron的问题,如果您发布Schematron,而不是发布从Schematron生成的XSLT,可能会更清楚。照原样,我使用了您的XSLT,将留给您来修改Schematron,使其以相同的方式工作。

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

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

第三,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>

答案 1 :(得分:0)

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

但是,我发现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

再次感谢您的有用添加和有用评论。