XSLT: использование пространства имен родительского узла

Я хотел бы избежать создания повторяющегося пространства имен в моем выводе XSLT.

(Я использую XSLT для обработки некоторого XML-кода, чтобы Microsoft DataContractSerializer счел нужным обработать его должным образом. Одна из вещей, которая, похоже, не нравится DCS, — это многократное определение одного и того же пространства имен.)

Я беру все элементы «Характеристики» из-под элемента XXX и группирую их вместе в новый элемент массива следующим образом:

<xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some namespace">
<xsl:template match="feature:XXX">
  <xsl:copy>
    <feature:Characteristics>
      <xsl:apply-templates select="feature:Characteristics"/>
     </feature:Characteristics>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>
<xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
</xsl:template>
</xsl:stylesheet>

Пространство имен «feature» определено в начале файла XSLT. Однако значение «feature» не будет найдено в исходном XML, это будет какой-то произвольный префикс (обычно «h»). Проблема в том, что если я использую этот XSLT, то пространство имен назначается двум префиксам в выходном XML: исходному пространству имен из входного XML (обычно «h») и «функции», сгенерированной XSLT. (Хотя это и допустимый XML, это сбивает с толку бедную Microsoft.)

Поэтому я хотел бы полностью избежать определения пространства имен "feature" в выходном XML, вместо этого ссылаясь на пространство имен текущего элемента. Я пробовал варианты, но я не знаю, как правильно установить значение пространства имен элемента xsl:, чтобы получить префикс пространства имен текущего узла контекста...

<xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some namespace">
  <xsl:template match="feature:XXX">
   <xsl:copy>
    <xsl:element name="Characteristics" namespace="{???}">
      <xsl:apply-templates select="feature:Characteristics"/>
    </xsl:element>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>
  <xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
</xsl:template>
</xsl:stylesheet>

Пример ввода:

<h:XXX xmlns:h="http://stackoverflow.com">
 <h:Characteristics>7</h:Characteristics>
 <h:Characteristics>11</h:Characteristics>
 <h:Characteristics>12</h:Characteristics>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

Повторять пространства имен (плохо):

<h:XXX xmlns:h="http://stackoverflow.com">
 <feature:Characteristic xmlns:feature="http://stackoverflow.com">
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">7</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">11</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">12</arrays:unsignedShort>
 </feature:Characteristic>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

Желаемый результат:

<h:XXX xmlns:h="http://stackoverflow.com">
 <h:Characteristic>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">7</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">11</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">12</arrays:unsignedShort>
 </h:Characteristic>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

Этот XSLT почти работает, но он требует жесткого кодирования значения «h», и вместо этого я хотел бы поддерживать произвольное значение:

<?xml version ="1.0" encoding="iso-8859-1"?>
  <xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some ns"
              xmlns:h="some ns"
              exclude-result-prefixes="h">

<xsl:template match="feature:XXX">
  <xsl:copy>
    <h:Characteristic>
      <xsl:apply-templates select="feature:Characteristics"/>
    </h:Characteristic>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>

<xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
 </xsl:template>

 </xsl:stylesheet>

person evilfred    schedule 05.01.2010    source источник
comment
не могли бы вы предоставить некоторые примеры данных?   -  person Rubens Farias    schedule 06.01.2010
comment
Используют ли элементы разные префиксы пространства имен, не должно иметь значения для механизма синтаксического анализа. Они будут расширены до одного и того же пространства имен-uri и будут представлять одно и то же имя элемента. С какими ошибками вы сталкиваетесь?   -  person Mads Hansen    schedule 06.01.2010
comment
Я использую его в качестве входных данных для DataContractSerializer, который, как мне кажется, молча не может установить значения членов, когда он встречает одно и то же пространство имен во второй раз. Устанавливается только значение элемента «Характеристики» или другие значения элемента, а не оба, в зависимости от порядка XSL.   -  person evilfred    schedule 06.01.2010


Ответы (3)


Если вам нужны согласованные префиксы пространств имен, вам нужно создать новые элементы, а не копировать. Установите свой префикс пространства имен на то, что вы хотите (функция, h и т. д.) в XSLT.

Следующий XSLT:

<xsl:stylesheet version="1.0"
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:feature="http://stackoverflow.com"
              xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="feature:XXX">
   <xsl:element name="feature:XXX">
    <feature:Characteristic>
      <xsl:apply-templates select="feature:Characteristics"/>
    </feature:Characteristic>
    <xsl:apply-templates select="*[not(self::feature:Characteristics)]" />
  </xsl:element>
  </xsl:template>

  <xsl:template match="feature:Characteristics">
    <xsl:element name="arrays:unsignedShort">
        <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

  <xsl:template match="*">
     <xsl:element name="feature:{local-name()}" >
        <xsl:value-of select="." />
     </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Генерирует следующий вывод:

<?xml version="1.0" encoding="UTF-16"?>
<feature:XXX xmlns:feature="http://stackoverflow.com">
 <feature:Characteristic xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <arrays:unsignedShort>7</arrays:unsignedShort>
  <arrays:unsignedShort>11</arrays:unsignedShort>
  <arrays:unsignedShort>12</arrays:unsignedShort>
 </feature:Characteristic>
 <feature:ProductName>blah</feature:ProductName>
 <feature:Vendor>blah</feature:Vendor>
 <feature:Version></feature:Version>
</feature:XXX>
person Mads Hansen    schedule 06.01.2010

Я только что удалил это пространство имен feature; если я правильно понял, он будет содержать тот же URI, что и h, верно?

<xsl:stylesheet version="1.0"
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:h="http://stackoverflow.com">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="h:XXX" >
    <xsl:copy>
      <h:Characteristics>
        <xsl:apply-templates select="h:Characteristics"/>
      </h:Characteristics>
      <xsl:copy-of select="*[not(self::h:Characteristics)]" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="h:Characteristics">
    <arrays:unsignedShort 
        xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
      <xsl:value-of select="." />
    </arrays:unsignedShort>
  </xsl:template>
</xsl:stylesheet>
person Rubens Farias    schedule 06.01.2010
comment
Пространство имен h будет определено во второй раз в элементе «Характеристики» в выходных данных, что не сработает для меня. - person evilfred; 06.01.2010
comment
Я не видел этого в своем окружении; как вы тестируете преобразование XSLT? - person Rubens Farias; 06.01.2010
comment
в C# // Загружаем таблицу стилей. XslCompiledTransform xslt = новый XslCompiledTransform(); xslt.Load (convertFilename); // Выполнить преобразование и вывести результаты в файл. xslt.Transform (исходный файл, blah.xml); - person evilfred; 06.01.2010

Кажется, это работает для меня, я уверен, что должен быть более простой способ, но в данный момент я не могу думать. Все это использует функцию name() для получения имени с префиксом корневого имени, substring-before() для получения префикса, затем перестраивает значения и выдает их. как неэкранированный текст.

<xsl:stylesheet version="1.0" 
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
          xmlns:feature="http://stackoverflow.com"
      exclude-result-prefixes="feature" >
<xsl:template match="feature:XXX">
  <xsl:variable name="p" select="substring-before(name(), ':')"/>
  <xsl:copy>
   <xsl:value-of select="concat('&lt;', $p,':Characteristic', '&gt;')" disable-output-escaping="yes"/>
   <xsl:apply-templates select="feature:Characteristics"/>
   <xsl:value-of select="concat('&lt;/', $p,':Characteristic', '&gt;')" disable-output-escaping="yes"/>
   <xsl:copy-of select="*[not(self::feature:Characteristics)]" /> 
 </xsl:copy>
</xsl:template>
  <xsl:template match="feature:Characteristics">
   <arrays:unsignedShort 
       xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
     <xsl:value-of select="." />
   </arrays:unsignedShort>
 </xsl:template>
</xsl:stylesheet>
person tyranid    schedule 06.01.2010