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
。请注意 c
与 C
.
其次,您可能需要在 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
再次感谢您的有益补充和有益评论。
背景 我有一个 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
。请注意 c
与 C
.
其次,您可能需要在 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
再次感谢您的有益补充和有益评论。