Не удается заставить копию узла XSLT работать при работе с двумя файлами XML - PullRequest
0 голосов
/ 15 марта 2012

У меня есть два XML-файла:

data1.xml

<?xml version="1.0" encoding="UTF-8"?>
<tables>
    <table>
        <row>
            <cell colname="1">A</cell>
            <cell colname="2">
                <carType>Sedan</carType>
                <gasType>Gasoline</gasType>
            </cell>
            <cell colnane="4">B</cell>
            <cell colname="5">C</cell>
        </row>
        <row>
            <cell colname="1">A1</cell>
            <cell colname="2">
                <carType>Truck</carType>
                <gasType>Diesel</gasType>
            </cell>
            <cell colname="4">B1</cell>
            <cell colname="5">C1</cell>
        </row>
    </table>
 </tables>

data2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tables>
    <table>
        <row>
            <cell colname="1">A</cell>
            <cell colname="2">
                <carType>SedanXYZ</carType>
                <gasType>GasolineXYZ</gasType>
            </cell>
            <cell colname="4">B</cell>
            <cell colname="5">C</cell>
        </row>
        <row>
            <cell colname="1">A2</cell>
            <cell colname="2">
                <carType>Motorcycle</carType>
                <gasType>Gasoline</gasType>
            </cell>
            <cell colname="4">U</cell>
            <cell colname="5">Z</cell>
        </row>
        <row>
            <cell colname="1">A1</cell>
            <cell colname="2">
                <carType>TruckXYZ</carType>
                <gasType>DieselXYZ</gasType>
            </cell>
            <cell colname="4">B1</cell>
            <cell colname="5">C1</cell>
        </row>
    </table>
 </tables>

По сути, я хочу скопировать все, что содержится в colname = "2", из data2.xml в data1.xml и оставить остальные данные в data1.xml такими же. Ключами для нахождения равенства являются colname = "4" и colname = "5". Мой XSLT выглядит так:

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

    <xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>

    <xsl:param name="doc2"/> 

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

    <xsl:template match="cell[@colname='2']">
        <xsl:variable name="key-value">
            <xsl:call-template name="key-value"/>
        </xsl:variable>

        <xsl:for-each select="document($doc2)//row">
           <xsl:if test="key('keyx', $key-value)">   
               <xsl:copy-of select="cell[@colname='2']"/>
           </xsl:if>
        </xsl:for-each>

    </xsl:template>

    <!-- Just copy any other elements, attributes, etc. -->
    <xsl:template match="@*|node()" >
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>


    <xsl:key name="keyx" match="row" 
    use="concat(cell[@colname='4'], cell[@colname='5'])"/>

    <!-- This template retrives the key value for an element -->
    <xsl:template name="key-value">
        <xsl:value-of select="concat(../cell[@colname='4'],../cell[@colname='5'])"/>
    </xsl:template>


</xsl:stylesheet>

Результат, который я ожидаю:

<?xml version="1.0" encoding="iso-8859-1"?>
<tables>
   <table>
       <row>
            <cell colname="1">A</cell>
            <cell colname="2">
                <carType>SedanXYZ</carType>
                <gasType>GasolineXYZ</gasType>
            </cell>
            <cell colname="4">B</cell>
            <cell colname="5">C</cell>
       </row>
       <row>
            <cell colname="1">A1</cell>
            <cell colname="2">
                <carType>TruckXYZ</carType>
                <gasType>DieselXYZ</gasType>
            </cell>
            <cell colname="4">B1</cell>
            <cell colname="5">C1</cell>
       </row>
   </table>
</tables>

BUT I'm getting incorrect output like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<tables>
    <table>
        <row>
            <cell colname="1">A</cell>
            <cell colname="2">
                <carType>SedanXYZ</carType>
                <gasType>GasolineXYZ</gasType>
            </cell>
            <cell colname="2">
                <carType>Motorcycle</carType>
                <gasType>Gasoline</gasType>
            </cell>
            <cell colname="2">
               <carType>TruckXYZ</carType>
               <gasType>DieselXYZ</gasType>
            </cell>
            <cell colname="4">B</cell>
            <cell colname="5">C</cell>
        </row>
        <row>
            <cell colname="1">A1</cell>
            <cell colname="2">
               <carType>SedanXYZ</carType>
               <gasType>GasolineXYZ</gasType>
            </cell>
            <cell colname="2">
               <carType>Motorcycle</carType>
               <gasType>Gasoline</gasType>
            </cell>
            <cell colname="2">
               <carType>TruckXYZ</carType>
               <gasType>DieselXYZ</gasType>
            </cell>
            <cell colname="4">B1</cell>
            <cell colname="5">C1</cell>
       </row>
    </table>
</tables>

Итак, несколько вопросов:

  1. Что не так с моим XSLT?
  2. Какая техника отладки вызовов клавиш?.

    Спасибо тебе.

    John

Ответы [ 2 ]

2 голосов
/ 15 марта 2012

Что не так с вашим кодом: вы используете key () без третьего аргумента. Третий аргумент сообщает системе, какой документ вы хотите искать. Если вы пропустите его, он выполнит поиск документа, содержащего контекстный узел, тогда как вы захотите найти «другой» документ. При выполнении такой задачи лучше всего иметь две глобальные переменные, содержащие два узла документа, чтобы вы могли легко переключаться между ними.

Лично я решаю эту задачу слияния, используя xsl: for-each-group. В атрибуте select для каждой группы выберите все соответствующие элементы из обоих документов. В теле for-each-group, если current-group () содержит один элемент, выведите его, в противном случае решите, какой из них вывести на основе теста, такого как root(.) is $doc-two.

1 голос
/ 15 марта 2012

Я думаю, вы не можете использовать здесь функцию ключа, потому что вам нужно создать набор ключей в $ doc2, а XML Spy не позволяет мне это делать.И ключа в исходном XML не хватит.
Поэтому я написал для вас другое решение, совсем не используя ключ:

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

    <xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>

    <xsl:param name="doc2"><xsl:copy-of select="document('C:\test\data2.xml')"/></xsl:param>

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

    <xsl:template match="cell[@colname='2']">
        <xsl:variable name="keyValue" select="concat(../cell[@colname='4'], ../cell[@colname='5'])"/>
        <xsl:for-each select="$doc2/tables/table/row[concat(cell[@colname='4'], cell[@colname='5']) = $keyValue]">
            <xsl:copy-of select="cell[@colname='2']"/>
        </xsl:for-each>
    </xsl:template>

    <!-- Just copy any other elements, attributes, etc. -->
    <xsl:template match="@*|node()" >
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

О, и, кстати, у вас есть пара colnane опечатки в исходных файлах.

EDIT забыли о третьем аргументе в ключевой функции :-(. Поэтому добавив

<xsl:key name="keyx" match="row" use="concat(cell[@colname='4'], cell[@colname='5'])"/>

и изменивкаждый на

    <xsl:for-each select="key('keyx', $keyValue, $doc2)">
        <xsl:copy-of select="cell[@colname='2']"/>
    </xsl:for-each>

достигнет ваших целей.

РЕДАКТИРОВАТЬ 2

ОК, вышеупомянутое заменяет ячейки colname = "2", но неоставьте данные data1, если совпадения data2 не найдены.

Вместо этого используйте следующее:

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

    <xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>

    <xsl:param name="doc2"/> <!-- supplied in parameter list in specific tool -->
    <xsl:key name="keyx" match="row" use="concat(cell[@colname='4'], cell[@colname='5'])"/>

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

    <xsl:template match="cell[@colname='2']">
        <xsl:variable name="keyValue" select="concat(../cell[@colname='4'], ../cell[@colname='5'])"/>
        <xsl:variable name="doc2Matches" select="key('keyx', $keyValue, document($doc2))"/>
        <xsl:choose>
            <xsl:when test="$doc2Matches">
                <xsl:copy-of select="$doc2Matches[1]/cell[@colname='2']"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- Just copy any other elements, attributes, etc. -->
    <xsl:template match="@*|node()" >
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
...