Сравнение 2-х XML средствами XSLT

3test

Новичок
Сравнение 2-х XML средствами XSLT

Мне нужно сравнить два XML документа средствами XSLT 1.0.
Шаблоны для сравнения двух узлов - я написал. Но, проблема в том, что я не знаю, как одновременно можно перебрать два набора узлов для их сравнения:

Код:
<xsl:variable name="A" select="document('file1.xml')"/> 
<xsl:variable name="B" select="document('file2.xml')"/>
в цикле можно перебрать только один набор:

<xsl:for-each select="$A/*">
...
</xsl:for-each>

это ограничение можно было б обойти, если с помощью вызова вспомогательного шаблона :

Код:
<xsl:template name="retrieve"> 
<xsl:param name="name" /> 
<xsl:param name="nodeSet" /> 

 _ <xsl:for-each select="$nodeSet"> 
 _ _ _<xsl:if test="name(.)=name($name)"> 
 _ _ _ _ <xsl:copy-of select="."/> 
 _ _ _</xsl:if> 
 _ </xsl:for-each> 
</xsl:template>
- можно было б вернуть узел со второго набора элементов.

Но при вызове

Код:
<xsl:variable name="node"> _ _
 _ <xsl:call-template name="retrieve"> 
 _ _ _ _ <xsl:with-param name="name" select="$e1/A1" /> 
 _ _ _ <xsl:with-param name="nodeSet" select="$e2/*" /> 
 _ </xsl:call-template> 
</xsl:variable>
возвращает только содержание узла.

<xsl:value-of select="name($node)"/> - для такого обращения происходит ошибка компиляции...

Не подскажете, как можно решить такую проблему? Как в XSLT 1.0 одновременно можно обойти два набора узлов?

У кого-то есть какие-то идеи по этому поводу?
 

Alexandre

PHPПенсионер
3test 1) решение не совсем для XSLT, соответственно в XSLT это будет немного криво.
2) используй связку <xsl:key><xsl:variable> и <xsl:call-template>
раскрывать не буду - это долго. копай в направлении <xsl:key>
теорию и примеры см. http://www.dpawson.co.uk/xsl/sect2/sect21.html
 

3test

Новичок
Автор оригинала: slach
зачем именно XSLT1.0 ??

по моему это какое то извращение
не спорю... но, у меня было такое задание на работе...

На основе:
http://www.dpawson.co.uk/xsl/sect2/N1777.html

Проблему удалось решить так:

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

<xsl:param name="file1"/>
<xsl:param name="file2"/>

  <xsl:variable name="A" select="document($file1)" />
  <xsl:variable name="B" select="document($file2)"/>




  <xsl:template match="/">
	
	<xsl:call-template name="cmpElements">
	 	<xsl:with-param name="e1" select="$A/*" />
    	<xsl:with-param name="e2" select="$B/*" />
	</xsl:call-template>

    <!-- Process all descendant nodes in A: -->
    <xsl:apply-templates select="$A/*//*" mode="A" />
    <!-- Process all descendant nodes in B: -->
    <xsl:apply-templates select="$B/*//*" mode="B" />
  </xsl:template>

  <xsl:template match="*" mode="A">

    <xsl:variable name="curname" select="name()" /> 
    <xsl:variable name="matching" select="$B/*//*[name() = $curname]"/>

 
      <xsl:choose>
        <xsl:when test="$matching">
<!-- <xsl:text>
</xsl:text> -->
			<xsl:call-template name="cmpElements">
		   		<xsl:with-param name="e1" select="." />
    			<xsl:with-param name="e2" select="$matching" />
			</xsl:call-template>
        </xsl:when>
        <xsl:otherwise> 
<xsl:value-of select="name()" />(only in A)
        </xsl:otherwise>
      </xsl:choose>

  </xsl:template>

  <xsl:template match="*" mode="B">
    <!-- Figure out whether this B node has a namesake in A.
         If not, mention it. -->
    <xsl:variable name="curname" select="name()" />
    <xsl:variable name="matching" select="$A/*//*[name() = $curname]"/>
    <xsl:if test="not($matching)">
<xsl:value-of select="name()" /> (only in B)
    </xsl:if>
  </xsl:template>

<!-- 
Compare two elements.
return error msg, or nothing
-->
<xsl:template name="cmpElements">
<xsl:param name="e1" />
<xsl:param name="e2" />

	<xsl:choose>
		<xsl:when test="name($e1)=name($e2)">
	
			<xsl:variable name ="atribEqual" >
				<xsl:call-template name="cmpAtr">
			   		<xsl:with-param name="e1" select="$e1" />
	    			<xsl:with-param name="e2" select="$e2" />
				</xsl:call-template>
			</xsl:variable>

			<xsl:choose>
				<!-- Compare attributes -->
				<xsl:when test="$atribEqual=''">
					<xsl:choose>
						<!-- Compare count of children of elements-->
					
						<xsl:when test="count($e1/*)=count($e2/*)">
							<xsl:if test="count($e1/*)=0 and $e1!=$e2">
Text values of elements /<xsl:value-of select="name($e1)"/>/<!-- and <xsl:value-of select="name($e2)"/>--> are not equal.
							</xsl:if>

						</xsl:when>
						<xsl:otherwise>
Elements /<xsl:value-of select="name($e1)"/>/<!-- and <xsl:value-of select="name($e2)"/>--> have different number of children.
						</xsl:otherwise>
				
					</xsl:choose>
				</xsl:when>
				<xsl:otherwise>
<xsl:value-of select="$atribEqual"/>
Attributes of elements <xsl:value-of select="name($e1)"/> and <xsl:value-of select="name($e2)"/> are not equal.
				</xsl:otherwise>		
			</xsl:choose>
	
		</xsl:when>
		<xsl:otherwise>
Elements names: <xsl:value-of select="name($e1)"/> and <xsl:value-of select="name($e2)"/> are not equal.	
		</xsl:otherwise>
	</xsl:choose>
	
</xsl:template>


<xsl:template name="atrExist">
<xsl:param name="atrName" />
<xsl:param name="atrSet" />
		<xsl:for-each select="$atrSet">
			<xsl:choose>
        		<xsl:when test="name(.)=$atrName">1</xsl:when>
			</xsl:choose>		
	</xsl:for-each>
	
</xsl:template>

<xsl:template name="getAtrVal">
<xsl:param name="atrName" />
<xsl:param name="atrSet" />

	<xsl:for-each select="$atrSet">
			<xsl:choose>
        		<xsl:when test="name(.)=$atrName">
        			<xsl:value-of select="."/>
        		</xsl:when>
        		
			</xsl:choose>		
	</xsl:for-each>

</xsl:template>

<!-- 
Compare attributes of two elements to equality.
params: elements
return nothing, or message about difference of attributes
-->
<xsl:template name="cmpAtr">
<xsl:param name="e1" /> 
<xsl:param name="e2" />
<!--<xsl:value-of select="count($e1/@*)"/>
<xsl:value-of select="name($e1/@*)"/>  
<xsl:text>
<xsl:value-of select="name($e2/@*)"/> 
<xsl:value-of select="count($e2/@*)"/> 
</xsl:text>  -->
	<xsl:choose>
        <xsl:when test="count($e1/@*)=count($e2/@*)">
			
			
        	<xsl:for-each select="$e1/@*">

				<xsl:variable name ="exist" >
					<xsl:call-template name="atrExist">
			    		<xsl:with-param name="atrName" select="name()" />
				    	<xsl:with-param name="atrSet" select="$e2/@*" />
					</xsl:call-template>
				</xsl:variable>
				
				<xsl:choose>
					<xsl:when test="$exist=1">

						<xsl:variable name ="atrVal" >
							<xsl:call-template name="getAtrVal">
					    		<xsl:with-param name="atrName" select="name()" />
						    	<xsl:with-param name="atrSet" select="$e2/@*" />
							</xsl:call-template>
						</xsl:variable>

						<xsl:if test="$atrVal!=string(.)">
Not equal attribute <xsl:value-of select="name()"/>
						</xsl:if>

					</xsl:when>
					<xsl:otherwise>
						Have not attribute <xsl:value-of select="name()"/>
					</xsl:otherwise>
				</xsl:choose>				
        	</xsl:for-each>
        	
        </xsl:when>
        <xsl:otherwise>
Elements have different number of attribute.
       	</xsl:otherwise>
    </xsl:choose>                    


</xsl:template>

</xsl:stylesheet>
 
Сверху