2012-06-18 1 views
10

Я работаю над XSLT, где мне нужно реализовать что-то следующим образом. Образец исходного кода XML выглядит так.Внедрение концепции ключевых значений в XSLT

<?xml version="1.0" encoding="ISO-8859-1"?> 
    <catalog> 
     <cd> 
      <title>A</title> 
      <title>B</title> 
      <title>C</title> 
     </cd> 
    </catalog> 

Рассмотрите, есть ли какой-либо ключевой пара значений пары.

Key   Value 
    A   Algebra 
    B   Biology 
    C   Chemistry 
    D   Data Analysis 
    ---   --- 

    ----  --- 

Мне нужно написать XSLT, что для каждого ключа вхождение «A», необходимо заменить соответствующее значение.

Мне также нужно указать список пар значений ключа в том же XSLT. Пример вывода:

<Data> 
    <Subject>Algebra</Subject> 
    <Subject>Biology</Subject> 
    <Subject>Chemistry</Subject> 
</Data> 

Может ли один помочь мне, как это сделать.

спасибо.

ответ

16

I. Простого XSLT 1.0 Решения

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

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<my:codes> 
    <code key="A" value="Algebra"/> 
    <code key="B" value="Biology"/> 
    <code key="C" value="Chemistry"/> 
    <code key="D" value="Data Analysis"/> 
</my:codes> 

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

<xsl:template match= 
    "title/text()[. = document('')/*/my:codes/*/@key]"> 

    <xsl:value-of select= 
    "document('')/*/my:codes/*[@key=current()]/@value"/> 
</xsl:template> 
</xsl:stylesheet> 

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

<catalog> 
    <cd> 
     <title>A</title> 
     <title>B</title> 
     <title>C</title> 
    </cd> 
</catalog> 

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

<catalog> 
    <cd> 
     <title>Algebra</title> 
     <title>Biology</title> 
     <title>Chemistry</title> 
    </cd> 
</catalog> 

Объяснение:

Это стандартный способ включения встроенного XML-узел, как глобальный элемент (дочерний элемент xsl:stylesheet), который принадлежит к (не пусто) пространство имен, отличное от пространства имен xsl.


II. Более эффективное решение XSLT 1.0, используя ключи:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:my="my:my"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <my:codes> 
     <code key="A" value="Algebra"/> 
     <code key="B" value="Biology"/> 
     <code key="C" value="Chemistry"/> 
     <code key="D" value="Data Analysis"/> 
    </my:codes> 

    <xsl:key name="kCodeByName" match="code" use="@key"/> 

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

    <xsl:template match= 
     "title/text()[. = document('')/*/my:codes/*/@key]"> 

     <xsl:variable name="vCur" select="."/> 

     <xsl:for-each select="document('')"> 
      <xsl:value-of select= 
      "key('kCodeByName', $vCur)/@value"/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

когда это преобразование применяется на том же самом документе XML (выше), то же самое правильное, хотел результат получается:

<catalog> 
    <cd> 
     <title value="Algebra"/> 
     <title value="Biology"/> 
     <title value="Chemistry"/> 
    </cd> 
</catalog> 

Пояснение:

Доступ к данным через функцию key(), как правило, является сублинейным - часто O (1) и является чрезвычайно низким чем линейный поиск (что важно, если количество поисковых узлов велико).

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


III. XSLT-раствор 2,0:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:variable name="vCodes"> 
    <codes> 
    <code key="A" value="Algebra"/> 
    <code key="B" value="Biology"/> 
    <code key="C" value="Chemistry"/> 
    <code key="D" value="Data Analysis"/> 
    </codes> 
</xsl:variable> 

<xsl:key name="kCodeByName" match="code" use="string(@key)"/> 

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

<xsl:template match= 
    "title/text()[key('kCodeByName', ., $vCodes)]"> 

    <xsl:sequence select= 
    "key('kCodeByName', ., $vCodes)/@value"/> 
</xsl:template> 
</xsl:stylesheet> 

когда это преобразование применяется на том же самом документе XML (выше), то же самое правильное, хотел результат получается:

<catalog> 
    <cd> 
     <title value="Algebra"/> 
     <title value="Biology"/> 
     <title value="Chemistry"/> 
    </cd> 
</catalog> 

Пояснение:

Практически то же, что и эффективное решение XSLT 1.0, но:

  1. В XSLT 2.0 шаблон соответствия шаблону может содержать ссылку на переменную.

  2. В XSLT 2.0 нет необходимости в акробатических трюках, управляющих текущими и проиндексированными документами. Третий аргумент функции key() - это указать дерево, индекс которого должен использоваться.

+0

Благодарим за ответ. – Patan

+0

@ User222: Добро пожаловать. –

+0

@Dimitre Можно ли назвать шаблон в решении III. XSLT 2.0 в другом шаблоне. Если да, пожалуйста, дайте мне знать, как это сделать? –