Адаптация XSLT для исключения атрибута из сравнения перед слиянием, но все же использование значения - PullRequest
2 голосов
/ 20 февраля 2011

У меня проблемы с адаптацией XSLT для обработки некоторых дополнительных правил / логики атрибутов.

У меня есть «общие» и «специальные» XML-файлы, которые я объединяю с этим XSLT: http://www2.informatik.hu -berlin.de / ~ obecker / XSLT / слияния / merge.xslt.html

Исходные файлы

general.xml

<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings e="2">
<language perm="RW">English</language>
<codec1_name idx="1" perm="">0</codec1_name>
<codec1_name idx="2" perm="">0</codec1_name>
</phone-settings>
</settings>

specific.xml

<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings e="2">
<language perm="RW">German</language>
<codec1_name idx="1" perm="R">8</codec1_name>
</phone-settings>
</settings>
  • XML-документы объединены, конкретные заменяет общие.
  • Если атрибуты и их значения точно совпадают, используются конкретные данные.

На данный момент преобразование работает хорошо, но я должен внести коррективы:

  • Некоторые элементы имеют атрибут 'idx', который уникально идентифицирует этот элемент
  • Некоторые элементы имеют атрибут 'perm', который определяет, будет ли пользователь читать / писать.

Если один и тот же элемент существует в обоих исходных файлах, но с другим атрибутом 'perm', XSLT считает его уникальным и вводится дублирующий элемент:

<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings e="2">
<language perm="RW">German</language>
<codec1_name idx="1" perm="">0</codec1_name>
<codec1_name idx="2" perm="">0</codec1_name>
<codec1_name idx="1" perm="R">8</codec1_name>
</phone-settings>
</settings>

Вот шаблон XSLT, который обрабатывает сравнение с одним узлом:

<xslt:template name="m:compare-nodes">
   <xslt:param name="node1" />
   <xslt:param name="node2" />
   <xslt:variable name="type1">
      <xslt:apply-templates mode="m:detect-type" select="$node1" />
   </xslt:variable>
   <xslt:variable name="type2">
      <xslt:apply-templates mode="m:detect-type" select="$node2" />
   </xslt:variable>

   <xslt:choose>
      <!-- Are $node1 and $node2 element nodes with the same name? -->
      <xslt:when test="$type1='element' and $type2='element' and local-name($node1)=local-name($node2) and namespace-uri($node1)=namespace-uri($node2) and name($node1)!=$dontmerge and name($node2)!=$dontmerge">
         <!-- Comparing the attributes -->
         <xslt:variable name="diff-att">
            <!-- same number ... -->
            <xslt:if test="count($node1/@*)!=count($node2/@*)">.</xslt:if>
            <!-- ... and same name/content -->
            <xslt:for-each select="$node1/@*">
               <xslt:if test="not($node2/@* [local-name()=local-name(current()) and namespace-uri()=namespace-uri(current()) and .=current()])">.</xslt:if>
            </xslt:for-each>
         </xslt:variable>
         <xslt:choose>
            <xslt:when test="string-length($diff-att)!=0">!</xslt:when>
            <xslt:otherwise>=</xslt:otherwise>
         </xslt:choose>
      </xslt:when>

      <!-- Other nodes: test for the same type and content -->
      <xslt:when test="$type1!='element' and $type1=$type2 and name($node1)=name($node2) and ($node1=$node2 or ($normalize='yes' and normalize-space($node1)= normalize-space($node2)))">=</xslt:when>

      <!-- Otherwise: different node types or different name/content -->
      <xslt:otherwise>!</xslt:otherwise>
   </xslt:choose>
</xslt:template>

Я могу исключить атрибут 'perm' из соответствия следующим образом:

<!-- ... and same name/content -->
<xslt:for-each select="$node1/@* [name(.)!='perm']">

Это решает проблему дублирования элементов, к сожалению, это также означает, что значение этого атрибута в конкретном XML-файле - в данном случае 'R' не объединяется:

<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings e="2">
<language perm="RW">German</language>
<codec1_name idx="1" perm="">8</codec1_name>
<codec1_name idx="2" perm="">0</codec1_name>
</phone-settings>
</settings>

Как я могу исключить атрибут 'perm' из теста уникальности, в то же время гарантируя, что его значение в определенном XML-файле используется при слиянии?

Желаемый результат объединения двух файлов примеров вверху:

<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings e="2">
<language perm="RW">German</language>
<codec1_name idx="1" perm="R">8</codec1_name>
<codec1_name idx="2" perm="">0</codec1_name>
</phone-settings>
</settings>

Любая помощь с этим будет высоко ценится!

Спасибо.

Ответы [ 2 ]

1 голос
/ 21 февраля 2011

Я могу исключить атрибут 'perm' из матча, выполнив это:

<!-- ... and same name/content -->

<xslt:for-each select="$node1/@*[name(.)!='perm']">

Это решает дубликат элемента вопрос, к сожалению, это также означает, что значение для этого атрибута в конкретный файл XML - «R» в этом дело не объединено

Как я могу исключить атрибут 'perm' из теста уникальности пока еще обеспечение его значения в конкретном XML файл используется при слиянии?

Из краткого прочтения довольно сложного кода слияния кажется, что вы можете достичь своей цели, изменив это (в строке 190):

<xsl:copy-of select="$first1/@*" />

с этим :

<xsl:copy-of select="$first2/@*" />

Заметьте : Лучшее решение, чем то, что вы в настоящее время делаете, - это ввести новый глобальный параметр, скажем, $ignore-attributes-in-comparison и указать в качестве значения разделенную пробелами строку с именами всех атрибутов, которые должны игнорироваться при сравнении узлов.

0 голосов
/ 21 февраля 2011

При другом подходе (идентифицировать элементы по имени и ключевым атрибутам) эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pSpecific" select="document('specific.xml')"/>
    <xsl:key name="kElemByName-Attr"
             match="*"
             use="concat(name(),'+',@idx,'+',@perm)"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[not(*)]">
        <xsl:param name="pSource" select="$pSpecific"/>
        <xsl:param name="pCopy" select="true()"/>
        <xsl:variable name="vCurrent" select="."/>
        <xsl:for-each select="$pSource">
            <xsl:variable name="vMatch"
                          select="key('kElemByName-Attr',
                                      concat(name($vCurrent),'+',
                                             $vCurrent/@idx,'+',
                                             $vCurrent/@perm))"/>
            <xsl:for-each select="$vMatch[$pCopy]">
                <xsl:call-template name="identity"/>
            </xsl:for-each>
            <xsl:for-each select="$vCurrent[not($vMatch)]">
                <xsl:call-template name="identity"/>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="*[*[not(*)]]">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <xsl:for-each select="$pSpecific">
                <xsl:variable name="vMatch"
                          select="key('kElemByName-Attr',
                                      concat(name($vCurrent),'+',
                                             $vCurrent/@idx,'+',
                                             $vCurrent/@perm))"/>
                <xsl:apply-templates select="$vMatch/node()">
                    <xsl:with-param name="pSource" select="$vCurrent"/>
                    <xsl:with-param name="pCopy" select="false()"/>
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выход:

<settings>
    <phone-settings e="2">
        <language perm="RW">German</language>
        <codec1_name idx="1" perm="">0</codec1_name>
        <codec1_name idx="2" perm="">0</codec1_name>
        <codec1_name idx="1" perm="R">8</codec1_name>
    </phone-settings>
</settings>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...