XSL: поверхностное сравнение двух XML-документов? - PullRequest
1 голос
/ 04 апреля 2011

Как мне сопоставить содержимое XML в XSLT?Я дам вам входные XML-файлы и ожидаемый вывод, а также то, что я пробовал:

input1.xml

  <?xml version="1.0" ?> 
  <list1>
   <value>1</value>
   <value>2</value>
   <value>3</value>
  </list1>

input2.xml (отредактировано, чтобы показать, что порядок не должензначения)

  <?xml version="1.0" ?> 
  <list2>
   <value>3</value>
   <value>1</value>
  </list2>

желаемый результат (отредактированный, чтобы показать, что порядок не имеет значения):

1 match
2 no match
3 match

или любая его перестановка.

Что я пробовал:

<xsl:variable name="list1" select="document('./resources/input1.xml')"/>
<xsl:variable name="list2" select="document('./resources/input2.xml')"/>

<xsl:for-each select="$list1/list1/value">
 <xsl:variable name="check"/>
 <xsl:variable name="list1_value" select="."/>
 <xsl:for-each select="$list2/list2/value">
  <xsl:if test="$list1_value=.">
   <xsl:variable name="check" select="1"/>
  </xsl:if>
 </xsl:for-each>
 <xsl:choose>
  <xsl:when test="$check='1'">
   <xsl:value-of select="."/> match<br />
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="."/> no match<br />
  </xsl:otherwise>
 </xsl:choose>
</xsl:for-each>

Конечно, это не работает, потому что он пытается использовать переменную в качестве переменной:)

Кроме того, как бы вы сопоставили больший список с XSLT, примененным к меньшему списку какнапример:

XSLT применяется к XML:

<?xml version="1.0" ?>
<list2>
 <value>1</value>
 <value>2</value>
</list2>

И этот список импортируется как переменная:

<?xml version="1.0" ?>
<list1>
 <value>1</value>
 <value>2</value>
 <value>3</value>
</list1>

Тот же желаемый результат.Спасибо!

1 Ответ

2 голосов
/ 04 апреля 2011

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <my:doc2>
    <list2>
        <value>1</value>
        <value>2</value>
    </list2>
 </my:doc2>

 <xsl:variable name="vDoc2"
      select="document('')/*/my:doc2/*"/>

 <xsl:template match="/*/*">
  <xsl:value-of select="concat('&#xA;  ',.,' ')"/>

  <xsl:variable name="vPos" select="position()"/>
   <xsl:if test="not(. = $vDoc2/*[position()=$vPos])">
    <xsl:text>no </xsl:text>
   </xsl:if>
   <xsl:text>match</xsl:text>
 </xsl:template>
</xsl:stylesheet>

при применении к первому предоставленному документу XML:

<list1>
    <value>1</value>
    <value>2</value>
    <value>3</value>
</list1>

дает желаемый, правильный результат:

  1 match
  2 match
  3 no match

Обновление : то же преобразование, но с двумя разными файлами XML:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pDoc1" select="'/temp/list1.xml'"/>
 <xsl:param name="pDoc2" select="'/temp/list2.xml'"/>

 <xsl:variable name="vDoc1"
      select="document($pDoc1)/*"/>
 <xsl:variable name="vDoc2"
      select="document($pDoc2)/*"/>

 <xsl:template match="/">
  <xsl:apply-templates select="$vDoc1/*"/>
 </xsl:template>

 <xsl:template match="/*/*">
  <xsl:value-of select="concat('&#xA;  ',.,' ')"/>

  <xsl:variable name="vPos" select="position()"/>
   <xsl:if test="not(. = $vDoc2/*[position()=$vPos])">
    <xsl:text>no </xsl:text>
   </xsl:if>
   <xsl:text>match</xsl:text>
 </xsl:template>
</xsl:stylesheet>

Update2 : OP дополнительно ищет решение, когда более короткие списки элементов для сравнения являются исходным документом XML:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:my="my:my">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <my:doc2>
      <list2>
        <value>1</value>
        <value>2</value>
        <value>3</value>
      </list2>
    </my:doc2>

    <xsl:variable name="vDoc1" select="/*"/>

    <xsl:variable name="vDoc2"
      select="document('')/*/my:doc2/*"/>

    <xsl:template match="/">
     <xsl:apply-templates select="$vDoc2/*"/>
    </xsl:template>
    <xsl:template match="value">
        <xsl:value-of select="concat('&#xA;  ',.,' ')"/>
        <xsl:variable name="vPos" select="position()"/>
        <xsl:if test="not(. = $vDoc1/*[position()=$vPos])">
            <xsl:text>no </xsl:text>
        </xsl:if>
        <xsl:text>match</xsl:text>
    </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к этому исходному XML-документу :

<list1>
    <value>1</value>
    <value>2</value>
</list1>

снова желаемый, правильный результат выдается :

  1 match
  2 match
  3 no match

Update3 : теперь третья модификация OP: порядок элементов в двух списках не имеет значения ...

Решение еще проще:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:my="my:my">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <my:doc2>
      <list2>
        <value>1</value>
        <value>2</value>
        <value>3</value>
      </list2>
    </my:doc2>

    <xsl:variable name="vDoc1" select="/*"/>

    <xsl:variable name="vDoc2"
      select="document('')/*/my:doc2/*"/>

    <xsl:template match="/">
     <xsl:apply-templates select="$vDoc2/*"/>
    </xsl:template>
    <xsl:template match="value">
        <xsl:value-of select="concat('&#xA;  ',.,' ')"/>
        <xsl:if test="not(. = $vDoc1/*)">
            <xsl:text>no </xsl:text>
        </xsl:if>
        <xsl:text>match</xsl:text>
    </xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...