XSLT: как удалить синонимы пространств имен - PullRequest
4 голосов
/ 15 марта 2011

У меня есть большая коллекция файлов XML, которые мне нужно преобразовать с помощью XSLT.Проблема в том, что многие из этих файлов были написаны от руки разными людьми, и они не используют непротиворечивые имена для ссылки на схемы.Например, один файл может использовать:

xmlns:itemType="http://example.com/ItemType/XSD"

, где другой может использовать префикс "it" вместо "itemType":

xmlns:it="http://example.com/ItemType/XSD"

Если это не так уж и плохо, есть несколько файлов, которые используют два или три синонима для одной и той же вещи!

<?xml version="1.0"?>
<Document
    xmlns:it="http://example.com/ItemType/XSD"
    xmlns:itemType="http://example.com/ItemType/XSD"
    xmlns:ItemType="http://example.com/ItemType/XSD"
    ...

(явно было много операций вырезания и вставки)

Теперь, поскольку сопоставление с образцом в файле XSLT, похоже, работает с префиксом пространства имен (в отличие от схемы, к которой оно относится), шаблон соответствует только одному из вариантов.Поэтому, если я напишу что-то вроде:

    <xsl:template match="SomeNode[@xsi:type='itemType:SomeType']">
        ...
    </xsl:template>

, тогда это будет соответствовать только подмножеству дел, которые я хочу.

Вопрос 1: Есть ли способчтобы XSLT соответствовал всем вариантам?

Вопрос 2: Есть ли способ удалить дубликаты, чтобы во всех выходных файлах использовалось согласованное именование?

Я наивнопопытался использовать "псевдоним пространства имен", но я думаю, что я неправильно понял, что это делает, потому что я не могу заставить его вообще что-либо делать - либо сопоставить все варианты, либо повлиять на выходной XML.

<?xsl:stylesheet
    version="1.0"
    ...
    xmlns:it="http://example.com/ItemType/XSD"
    xmlns:itemType="http://example.com/ItemType/XSD"
    xmlns:ItemType="http://example.com/ItemType/XSD"
    ...

    <xsl:output method="xml" indent="yes"/>
    <xsl:namespace-alias stylesheet-prefix="it" result-prefix="ItemType"/>
    <xsl:namespace-alias stylesheet-prefix="itemType" result-prefix="ItemType"/>

Ответы [ 2 ]

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

В XSLT 2.0 (независимо от того, используете ли вы схему) или нет, вы можете записать предикат как [@xsi:type=xs:QName('it:SomeType')], где «это» - префикс, объявленный в таблице стилей для этого пространства имен. Он не должен совпадать с префиксом, используемым в исходном документе.

Конечно, при сопоставлении имен элементов и атрибутов (в отличие от содержимого, имеющего значение QName) используются URI пространства имен, а не префиксы в XSLT 1.0 и XSLT 2.0.

1 голос
/ 15 марта 2011

Значения атрибутов или текстовые узлы не будут преобразованы в QName, если вы прямо не укажете это.Хотя это возможно только в XSLT / XPath 2.0

В XSLT / XPath 1.0 вы должны сделать это «вручную»:

<xsl:template match="SomeNode">
    <xsl:variable name="vPrefix" select="substring-before(@xsi:type,':')"/>
    <xsl:variable name="vNCName" 
           select="translate(substring-after(@xsi:type,$vPrefix),':','')"/>
    <xsl:if test="namespace::*[
                     name()=$vPrefix
                  ] = 'http://example.com/ItemType/XSD'
                     and
                  $vNCName = 'SomeType'">
        <!-- Content Template -->
    <xsl:if>
</xsl:template>

Редактировать: Все в одном шаблоне(менее читабельно, может быть):

<xsl:template match="SomeNode[
                        namespace::*[
                           name()=substring-before(../@xsi:type,':')
                        ] = 'http://example.com/ItemType/XSD'
                           and
                        substring(
                          concat(':',@xsi:type),
                          string-length(@xsi:type) - 7
                        ) = ':SomeType'
                     ]">
    <!-- Content Template -->
</xsl:template>
...