xsltproc слияние XML-файлов не работает - PullRequest
0 голосов
/ 21 мая 2018

Привет! Мне нужно xml-файлы для слияния по следующему условию:

Скопируйте все существующие узлы нового файла и затем объедините со старыми значениями файла.Например:

Файл abc.xml

<?xml version="1.0"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

Файл xyz.xml

<?xml version="1.0"?>
<schedule>
    <Item Id="1">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="4">
        <measurements>
            <measurement>Beta</measurement>
        </measurements>
    </Item>
</schedule>

Файл логики xslt: logic.xslt

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

<xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

<xsl:template match="Item">
    <xsl:variable name="match" select="document('./abc.xml')/schedule/Item[measurements/measurement=current()/measurements/measurement]"/>
    <xsl:choose>
        <xsl:when test="$match">
            <xsl:copy-of select="$match"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

Используемая команда:

xsltproc logic.xslt xyz.xml > output.xml

Ожидаемый результат:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="4">
        <measurements>
            <measurement>Beta</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

Но фактическое значение отличается от ожидаемого, а именно:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

Он пропускает узлы из нового XML-файла.

1 Ответ

0 голосов
/ 21 мая 2018

Изменить

<xsl:choose>
    <xsl:when test="$match">
        <xsl:copy-of select="$match"/>
    </xsl:when>
</xsl:choose>

на

<xsl:choose>
    <xsl:when test="$match">
        <xsl:copy-of select="$match"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:copy-of select="."/>
</xsl:choose>

С редактированием вопроса и дополнительными элементами из второго документа, которые необходимо скопировать, я думаю, что проблема сложнее, с XSLT3 вы можете сделать это, как в https://xsltfiddle.liberty -development.net / pPqsHTf

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

    <xsl:param name="doc1" select="/"/>

    <xsl:param name="doc2">
        <schedule>
            <Item Id="2">
                <measurements>
                    <measurement>Alpha</measurement>
                </measurements>
            </Item>
            <Item Id="9">
                <measurements>
                    <measurement>Gamma</measurement>
                </measurements>
            </Item>
        </schedule>      
    </xsl:param>

    <xsl:key name="ref" match="Item" use="measurements/measurement"/>

    <xsl:template match="schedule">
        <xsl:copy>
            <xsl:apply-templates select="Item, $doc2/schedule/Item[not(key('ref', measurements/measurement, $doc1))]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Item[root() is $doc1 and key('ref', measurements/measurement, $doc2)]">
        <xsl:copy-of select="key('ref', measurements/measurement, $doc2)"/>
    </xsl:template>

</xsl:stylesheet>

(конечно, вместо того, чтобы использовать второй встроенный документ, вы бы использовали <xsl:param name="doc2" select="document('abc.xml')"/>), но сXSLT 1 труднее работать с переменными и ключами, и вы не можете использовать их в шаблонах совпадений, поэтому кажется, что подход требует, как в https://xsltfiddle.liberty -development.net / pPqsHTf / 2

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">


    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

    <xsl:param name="doc1" select="/"/>

    <xsl:param name="doc2-rtf">
        <schedule>
            <Item Id="2">
                <measurements>
                    <measurement>Alpha</measurement>
                </measurements>
            </Item>
            <Item Id="9">
                <measurements>
                    <measurement>Gamma</measurement>
                </measurements>
            </Item>
        </schedule>      
    </xsl:param>

    <xsl:param name="doc2" select="exsl:node-set($doc2-rtf)" xmlns:exsl="http://exslt.org/common"/>

    <xsl:template match="schedule">
        <xsl:copy>
            <xsl:apply-templates select="Item"/>
            <xsl:copy-of select="$doc2/schedule/Item[not(measurements/measurement = $doc1//Item/measurements/measurement)]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Item">
        <xsl:choose>
            <xsl:when test="measurements/measurement = $doc2//Item/measurements/measurement">
                <xsl:copy-of select="$doc2//Item[measurements/measurement = current()/measurements/measurement]"/>              
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

конечно, опять же, просто используя <xsl:param name="doc2" select="document('abc.xml')"/> вместо того, чтобы данные были встроены (что я только сделал, чтобы получить полный пример и которое, к сожалению, с XSLT 1, затем требует использования функции расширения набора узлов).

...