Использование XPATH для выбора из определенного диапазона повторяющихся узлов - PullRequest
0 голосов
/ 21 ноября 2011

Я пытаюсь проанализировать документ, имеющий следующую (значительно упрощенную) структуру.Каждый документ может иметь один или несколько сегментов ORB, за которыми следует один или несколько сегментов OBX.Сегменты OBX относятся непосредственно к предыдущему сегменту OBR.

<obr> ...... </obr>
<obx> ...... </obx>
<obx> ...... </obx>
<obx> ...... </obx>
<obr> ...... </obr>
<obx> ...... </obx>
<obx> ...... </obx>

Ниже приведен более подробный, хотя и упрощенный пример:

<OBR>
    <OBR.1>
        <OBR.1.1>1</OBR.1.1>
    </OBR.1>
    <OBR.2/>
    <OBR.3>
        <OBR.3.1>12345678</OBR.3.1>
        <OBR.3.2>PLS</OBR.3.2>
    </OBR.3>
    <OBR.4>
        <OBR.4.1>CRP, LFT, Ue</OBR.4.1>
        <OBR.4.2>C Reactive protein, Liver Function Tests, Urea, Elec, Creat</OBR.4.2>
        <OBR.4.3>PLS</OBR.4.3>
    </OBR.4>
</OBR>
<OBX>
    <OBX.1>
        <OBX.1.1>1</OBX.1.1>
    </OBX.1>
    <OBX.2>
        <OBX.2.1>NM</OBX.2.1>
    </OBX.2>
    <OBX.3>
        <OBX.3.1>CRP</OBX.3.1>
        <OBX.3.2>C-Reactive Protein</OBX.3.2>
        <OBX.3.3>PLS</OBX.3.3>
    </OBX.3>
</OBX>

Мне нужно разработать и выражение xPath / код Javaкоторый может извлекать текст из определенного сегмента OBR вместе с кратным текстом.Извлечь индекс OBX.3.2 во всем документе просто, используя:

public Object read(String expression, QName returnType, int index) {
    expression = "(" + expression + ")[" + Integer.toString(index) + "]";
    try {
        XPathExpression xPathExpression = xPath.compile(expression);
        return xPathExpression.evaluate(xmlDocument, returnType);
    } catch (XPathExpressionException ex) {
        ex.printStackTrace();
        return null;
    }
}

Но я не уверен, как найти индекс OBX.3.2, связанный, скажем, со вторым OBR илидействительно, как посчитать количество сегментов OBX для каждого OBR (если я это новое, я, вероятно, мог бы решить проблему).Любое руководство или совет будет высоко ценится.

Я также попробовал метод Кейса ($ ns1 [count (. | $ Ns2) = count ($ ns2)]) для подсчета элементов, дающих:

count( //OBR[3]/following-sibling::OBX [ count (.|//OBR[4]/preceding-sibling::OBX) = count(//OBR[4]/preceding-sibling::OBX )])

Это выражение дает число элементов OBX ниже индексированного OBR и следующего OBR.Однако он неправильно обрабатывает последний OBR в группе (поскольку после него нет ORB)

Ответы [ 2 ]

1 голос
/ 21 ноября 2011

Я бы преобразовал исходный XML в более удобную форму с помощью XSLT и занялся бы результатом.

Пример преобразования XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

<xsl:template match="OBR">
    <xsl:variable name="$cur_OBR" select="."/>
    <xsl:variable
        name="obx"
        select="following-sibling::OBX[preceding-sibling::OBR[1] = $cur_OBR]"/>

    <OBR position="{position()}">
        <xsl:for-each select="*/*">
            <xsl:variable name="suffix"
                          select="substring-after(name(), 'OBR')"/>
            <xsl:variable name="rel_obx"
                          select="$obx/*/*[ends-with(name(), $suffix)]"/>
            <xsl:apply-templates select="." mode="sub_OBR">
                <xsl:with-params name="suffix" select="$suffix"/>
                <xsl:with-params name="rel_obx" select="$rel_obx"/>
            </xsl:apply-templates>
        </xsl:for-each>
    </OBR>
</xsl:template>

<xsl:template match="OBX"/>

<xsl:template mode="sub_OBR" match="*">
    <xsl:param name="suffix" select="substring-after(name(), 'OBR')"/>
    <xsl:param name="rel_obx"/>

    <xsl:element name="concat('OBR', $suffix)">
        <OBR>
            <xsl:apply-templates select="text()"/>
        </OBR>
        <xsl:for-each select="$rel_obx">
            <OBX>
                <xsl:apply-templates select="text()"/>
            </OBX>
        </xsl:for-each>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

Я не запускал его, хотя, чтобы проверить, является ли он абсолютно правильным. Вы также можете видеть, что вам потребуется переменная для выбора соответствующих элементов OBX для OBR с xpath: following-sibling::OBX[preceding-sibling::OBR[1] = $cur_OBR].

0 голосов
/ 05 декабря 2011

В случае, если другие наткнуться на это: решение для подсчета сегментов довольно просто:

Для подсчета OBX после i'го OBR:

count(//OBR[i]/following-sibling::OBX) - count(//OBR[i+1]/following-sibling::OBX) 

После этого становится возможным циклически проходить через соответствующие сегменты, используя код считывателя, приведенный выше.

...