2013-12-13 4 views
2

Мне нужно установить пространство имен в таблице стилей XSLT во время выполнения. Вот мой XSL:Как установить имя пространства имен в XSLT с помощью параметра

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tdns="{$myNS}"> 
    <xsl:output method="xml" encoding="iso-8859-1" /> 

    <xsl:param name="myNS" required="yes" /> 

    <xsl:template match="*"> 

     <xsl:choose> 
      <xsl:when test="name(.)='bugs'"> 
       <xsl:element name="tdns:bugs"> 

        <xsl:for-each select="*"> 
         <xsl:apply-templates select="." /> 
        </xsl:for-each> 
       </xsl:element> 
      </xsl:when> 
      <xsl:when test="name(.)='bug'"> 

       <xsl:element name="tdns:bug"> 
        <xsl:for-each select="*"> 
         <xsl:choose> 
          <xsl:when test="name(.)='Device' "> 
           <xsl:choose> 
            <xsl:when test="string-length(../tdns:Device_Tmp) &gt; 0 "> 
             <xsl:element name="tdns:Device"> 

              <xsl:value-of select="../tdns:Device_Tmp" /> 
             </xsl:element> 
            </xsl:when> 
            <xsl:otherwise> 
             <xsl:element name="tdns:Device"> 
              <xsl:value-of select="." /> 
             </xsl:element> 
            </xsl:otherwise> 
           </xsl:choose> 
           <xsl:element name="tdns:ShowParamValue"> 
            <xsl:value-of select="$myNS" /> 
           </xsl:element> 
          </xsl:when> 

         </xsl:choose> 
        </xsl:for-each> 
       </xsl:element> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

Входной XML

<?xml version="1.0" encoding="ISO-8859-1"?> 
<bugs xmlns="http://my.com"> 
    <bug> 
     <Device> 
      <![CDATA[Dev1]]> 
     </Device> 
     <Device_Tmp> 
      <![CDATA[Dev_tmp1]]> 
     </Device_Tmp> 
    </bug> 
</bugs> 

Java код

TransformerFactory tfactory = TransformerFactory.newInstance(); 
Transformer transformer = tfactory.newTransformer(new StreamSource(
     new File(xsl))); 
transformer.setParameter("myNS", "http://my.com"); 
transformer.transform(new StreamSource(new File(
     xml)), 
     new StreamResult(System.out)); 

Выходной XML

<?xml version="1.0" encoding="iso-8859-1"?> 
<tdns:bugs xmlns:tdns="http://my.com"> 
    <tdns:bug> 
     <tdns:Device> 
      Dev1 
     </tdns:Device> 
     <tdns:ShowParamValue>http://my.com</tdns:ShowParamValue> 
    </tdns:bug> 
</tdns:bugs> 

Как вы можете видеть, XSLT не знает любой ../tdns:Device_Tmp узла, но если я установить статические имена:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tdns="http://my.com"> 
... 

Затем результат OK:

<?xml version="1.0" encoding="iso-8859-1"?> 
<tdns:bugs xmlns:tdns="http://my.com"> 
    <tdns:bug> 
     <tdns:Device> 
      Dev_tmp1 
     </tdns:Device> 
     <tdns:ShowParamValue>http://my.com</tdns:ShowParamValue> 
    </tdns:bug> 
</tdns:bugs> 

Пожалуйста, скажи мне, что я делаю неправильно.

+1

Перед запуском программы может потребоваться предварительная обработка файла XSLT. Другими словами, выполните подстановку параметров для пространства имен и запишите результат в файл, который вы затем запустите в входном файле XML. –

+0

Возможный дубликат http://stackoverflow.com/questions/11795943/xslt-create-a-namespace-dynamically –

ответ

0

Похоже, что входные узлы не находятся в пространстве имен http://my.com. Вы можете видеть это, потому что имя (.) = 'Bugs' появляется для возврата true. Функция name() возвращает расширенное QName, которое должно включать пространство имен (в отличие от local-name()).

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

+0

Не совсем. Функция name() возвращает QName, которое представляет расширенное имя. Когда существует пространство имен по умолчанию, имя() необязательно возвращает QName с префиксом для каждого квалифицированного имени. –

1

Декларации пространства имен не являются атрибутами и не рассматриваются как шаблоны значений атрибутов (на самом деле они обрабатываются парсером XML, который анализирует документ таблицы стилей, прежде чем он приближается к XSLT-процессору).

Чтобы создать элементы с атрибутами name и namespace, вам нужно будет использовать <xsl:element>, чтобы иметь возможность динамически указывать пространство имен. Для сопоставления элементов самым простым подходом могло бы быть полное игнорирование пространств имен (поскольку вы находитесь в XSLT 2.0, это легко с *:localname).

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" encoding="iso-8859-1" /> 

    <xsl:param name="myNS" required="yes" /> 

    <!-- this will cover most things, including a Device that doesn't have a 
     sibling Device_Tmp --> 
    <xsl:template match="*"> 
     <xsl:element name="tdns:{local-name()}" namespace="{$myNS}"> 
     <xsl:apply-templates /> 
     </xsl:element> 
    </xsl:template> 

    <!-- delete Device_Tmp --> 
    <xsl:template match="*:Device_Tmp" /> 

    <!-- special case for Device elements that have a non-empty sibling 
     Device_Tmp --> 
    <xsl:template match="*:Device[string-length(../*:Device_Tmp) > 0]" 
        priority="2"> 
     <xsl:element name="tdns:{local-name()}" namespace="{$myNS}"> 
     <xsl:value-of select="../*:Device_Tmp" /> 
     </xsl:element> 
    </xsl:template> 

    <!-- add debugging element to bug --> 
    <xsl:template match="*:bug"> 
     <xsl:element name="tdns:{local-name()}" namespace="{$myNS}"> 
     <xsl:apply-templates /> 
     <xsl:element name="tdns:ShowParamValue" namespace="{$myNS}"> 
      <xsl:value-of select="$myNS" /> 
     </xsl:element> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
Смежные вопросы