Преобразуйте теги XML в атрибуты в произвольных местах с помощью XSLT - PullRequest
2 голосов
/ 16 декабря 2010

У нас есть формат XML, который на самом деле представляет собой просто HTML с некоторыми дополнительными шаблонами. Он определяет, какие элементы HTML доступны для редактирования, а какие атрибуты являются редактируемыми.

Вот пример

<img src="images/placeholder.jpg" 
     alt="Placeholder" 
     width="600" 
     height="250" 
     border="0">
  <var attr="src" />
  <var attr="height" ok="150-300" />
</img>

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

<img src="images/placeholder.jpg" 
     alt="Placeholder" 
     width="600" 
     height="250" 
     border="0"
     editable="src height" 
     constraints="height:150-300">

Я могу сделать это для <img>, но проблема в том, что теги <var> могут фактически появляться как дочерние элементы любого элемента на странице. Во всех случаях алгоритм преобразования его в атрибуты один и тот же, но я не могу понять, как это сделать, это указать шаблон XSLT, который может соответствовать родительскому элементу тега <var>. Я пытался match="var/..", но это оказалось недействительным.

Альтернативой может быть сопоставление <var> s и добавление их в качестве атрибутов их родителям, но я считаю, что на этом этапе обработки этот конкретный корабль уже проплыл.

Это выполнимо?

Thankies

Ответ!

Я объединил более полный ответ с полезным и точным ответом Димитра, чтобы получить следующее:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="*[var]">
        <xsl:copy >
            <xsl:attribute name="editable">
                <xsl:for-each select="var[@attr]">
                    <xsl:value-of
                        select="concat(@attr,
                            substring(' ',
                                1 div (position()!=last())))"/>
                </xsl:for-each>
            </xsl:attribute>
            <xsl:attribute name="constraints">
                <xsl:for-each select="var[@ok]">
                    <xsl:value-of
                        select="concat(@attr,':',@ok,
                            substring(';',
                                1 div (position()!=last())))"/>
                </xsl:for-each>
            </xsl:attribute>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="var">
    </xsl:template>

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

К сожалению, точный ответ, который дал Алехандро, сразу не сработал (но до сих пор не уверен, почему), но эта комбинация его ответа и ответа Дмитрия, похоже, хорошо сработала:)

Ответы [ 3 ]

4 голосов
/ 16 декабря 2010

что я не могу понять, как это сделать, это указать шаблон XSLT, который может соответствовать родительскому элементу тега <var>

Использовать :

<xsl:template match="*[var]">
1 голос
/ 17 декабря 2010

Помимо точного ответа Димитра на ваш вопрос, другой подход будет:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|var"/>
            <xsl:apply-templates select="node()[not(self::var)]"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="var"/>
    <xsl:template match="var[1]">
        <xsl:attribute name="editable">
            <xsl:for-each select="../var/@attr">
                <xsl:value-of
                     select="concat(.,
                                    substring(' ',
                                              1 div (position()!=last())))"/>
            </xsl:for-each>
        </xsl:attribute>
        <xsl:attribute name="constraints">
            <xsl:for-each select="../var/@ok">
                <xsl:value-of
                     select="concat(../@attr,':',.,
                                    substring(';',
                                              1 div (position()!=last())))"/>
            </xsl:for-each>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<img src="images/placeholder.jpg" 
     alt="Placeholder" 
     width="600" 
     height="250" 
     border="0" 
     editable="src height" 
     constraints="height:150-300"></img>
1 голос
/ 16 декабря 2010

Я хотел бы рассмотреть возможность создания локальной переменной (<xsl:variable>), когда парсер попадет в тег <img> и явно создаст NEW <img ...> внутри этой переменной, проходя через любые <var> дочерние элементы, которые он найдет (<xsl:foreach ...>) кто-нибудь?) закройте переменную, когда они исчерпаны ... затем просто запишите переменную?

...