xpath, чтобы увидеть, существует ли текущий узел в атрибуте набора узлов внешнего файла.

Предыстория У меня есть проверка схемы и перевод 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>

Extract from the sample 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>

I need to validate this using xpath. I've tried applying this contains instruction w/o much luck, and I've been searching but to no avail.

Проблема в том, что он всегда отображается как истина, даже при использовании 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-документе, поэтому он имеет такую ​​структуру. Я подумал, что если я буду использовать его повторно, его будет меньше поддерживать.


person Arizon    schedule 27.11.2018    source источник
comment
Я думаю вместо g[contains(@name,.)] вы хотите сравнить g[contains(@name, current()]. Точка . в вашей попытке относится к элементу g, на который вы поместили предикат.   -  person Martin Honnen    schedule 27.11.2018
comment
Спасибо! Вы правы, однако проверка все равно проходит, даже если значение не существует в списке допустимых значений атрибута. Есть ли очевидная логическая ошибка в выражении xpath, которую я не нашел?   -  person Arizon    schedule 28.11.2018
comment
Боюсь, я не понял, какая проверка должна идти, непонятно. Постарайтесь свести проблему к минимальным, но полным образцам XSLT и XML, а также требуемым выводам и текущим выводам, чтобы другие могли воспроизвести проблему. Учитывая, что, по крайней мере, некоторые из ваших примеров XML используют различные пространства имен, совершенно неясно, что соответствует вашим шаблонам соответствия XSLT, и ваши выражения XPath вообще выбирают, не видя полных примеров XSLT с объявлениями пространств имен (и объявлениями xpath-default-namespace?).   -  person Martin Honnen    schedule 28.11.2018


Ответы (2)


Поскольку это вопрос Schematron, было бы понятнее, если бы вы разместили Schematron, а не XSLT, который создается из Schematron. Как бы то ни было, я работал с вашим XSLT, и я оставлю вам возможность модифицировать ваш Schematron, чтобы он работал так же.

Во-первых, ваш текущий XSLT соответствует medicalFieldcode, а не medicalFieldCode. Обратите внимание на c против C.

Во-вторых, вам, вероятно, понадобится пространство имен в 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>
person Tony Graham    schedule 28.11.2018
comment
Спасибо за очень полезный вклад по этому вопросу и дальнейшее объяснение того, как работает schematron! Я обновлю комментарий о том, как я это решил. - person Arizon; 29.11.2018

Как отмечает Тони Грэм, Xpath, вероятно, можно упростить, используя вместо этого exists. И type:o я тоже упустил из виду. Отсутствующее пространство имен в контексте xpath также верно. Спасибо, что указали на эти вещи!

Однако я обнаружил, что в файле схемы уже есть правило для того же узла xml выше. В итоге я добавил к этому еще один <assert>, и это сработало (наряду с некоторыми другими изменениями).

Вот как это выглядит сейчас в файле схемы:

<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

Еще раз спасибо за ваши полезные дополнения и полезные комментарии.

person Arizon    schedule 29.11.2018