XSLT 2.0: поиск недостающих элементов в последовательности - PullRequest
2 голосов
/ 11 марта 2012

Мне нужно искать диапазон элементов на основе идентификационных номеров. Если идентификационный номер найден, я обработаю его. Если идентификатор не найден, он будет заполнен значением по умолчанию. Я использую XSLT 2.0 в Saxon 9.4 HE.

Вот очень упрощенный пример. Входной XML выглядит так:

<root>
    <item>
        <id>1</id>
    </item>
    <item>
        <id>2</id>
    </item>
    <item>
        <id>4</id>
    </item>
</root>

Если я ищу элементы с идентификатором 1, 2 или 3, я бы хотел получить следующий вывод. Обратите внимание, что я не хочу вывод для элемента 4.

Found 1
Found 2
Didn't find 3

Моя первая попытка была с циклом for-each, но он даже не компилируется. Я получаю сообщение об ошибке: «XPTY0020: шаг Axis child :: element ('': id) не может быть использован здесь: элемент контекста является атомарным значением" из строки "".

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:variable name="ids" select="(1, 2, 3)"/>

<xsl:template match="/root">
    <xsl:for-each select="$ids">
        <xsl:choose>
            <xsl:when test="count(item/id = .) > 0">
                Found <xsl:value-of select="."/>
            </xsl:when>
            <xsl:otherwise>
                Didn't find <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template> 

</xsl:stylesheet>

После этого я понял, что могу легко найти подходящие со следующими, но я не могу найти способ найти недостающие.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:variable name="ids" select="(1, 2, 3)"/>

<xsl:template match="/">
    <xsl:apply-templates select="root/item[id=$ids]"/>
</xsl:template> 

<xsl:template match="item">
    Found <xsl:value-of select="id"/>
</xsl:template> 

</xsl:stylesheet>

Кстати, выходные данные также должны быть отсортированы по идентификатору, что означает, что выгрузка списка всех найденных элементов с последующим списком не найденных элементов не будет работать. Это вообще возможно, или я должен пойти по легкой / слабой дороге и изменить свой ввод?

Ответы [ 2 ]

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

Вот более простое (без явных условий) и более короткое решение :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output method="text"/>

 <xsl:key name="kIdByVal" match="id" use="."/>

 <xsl:param name="psortedIds" as="xs:string+"
      select="'1','2','3'"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="/*">
  <xsl:for-each select="$psortedIds">
   <xsl:sequence select=
   '("found ", "didn&apos;t find ")
       [2 - number(boolean(key("kIdByVal", current(), $vDoc)))],
    ., "&#xA;"
   '/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование XSLT 2.0 применяется к предоставленному документу XML :

<root>
    <item>
        <id>1</id>
    </item>
    <item>
        <id>2</id>
    </item>
    <item>
        <id>4</id>
    </item>
</root>

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

found  1 
 found  2 
 didn't find  3 
1 голос
/ 11 марта 2012

Вот пример:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:key name="k1" match="item" use="number(id)"/>

<xsl:param name="ids" select="(1, 2, 3)"/>

<xsl:template match="/">
    <xsl:variable name="root" select="."/>
    <xsl:for-each select="$ids">
      <xsl:choose>
        <xsl:when test="key('k1', ., $root)">
          <xsl:text>Found </xsl:text>
          <xsl:value-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>Didn't find </xsl:text>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template> 

</xsl:stylesheet>

[править] Ваша первоначальная попытка была правильной, поскольку при обработке последовательности идентификаторов речь идет, но вам необходимо сохранить основной входной документ за пределами фор-каждый, поскольку внутри элемента контекста есть значение идентификатора, и без внешней переменной вы не сможете получить доступ к элементам элемента в документе.

И для эффективности я добавил ключ.

...