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

#xml #xslt

#xml #xslt

Вопрос:

Это мой XML:

 <?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="test_2.xsl" type="text/xsl"?>

<doc xmlns="http://www.foo.org">
  <div>
    <title>Mr. Title</title>
    <paragraph>This is one paragraph.
    </paragraph>
    <paragraph>Another paragraph.
    </paragraph>
    <list>
      <orderedlist>
        <item>
          <paragraph>An item paragraph.</paragraph>
        </item>
        <item>
          <paragraph>Another item paragraph</paragraph>
        </item>
      </orderedlist>
    </list>
  </div>    
</doc>
  

Мой XML удаляет список, изменяет orderedlist на ol, изменяет item на li. Теперь я хотел бы избавиться от узлов абзаца, которые являются дочерними элементами элемента, при переносе текста в новый li. Обратите внимание, что я не хочу избавляться от узлов абзаца, которые НЕ являются дочерними элементами элемента.

Пока это мой XSLT:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foo="http://www.foo.org">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

 <xsl:template match="foo:doc">
  <xsl:element name="newdoc" namespace="http://www/w3.org/1999/xhtml">
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="foo:div">
  <segment title="{foo:title}">
   <xsl:apply-templates/>
  </segment>
 </xsl:template>

 <xsl:template match="foo:title">
  <xsl:element name="h2">
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="foo:paragraph">
  <xsl:element name="p">
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="foo:list">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="foo:orderedlist">
  <xsl:element name="ol">
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="foo:item">
  <xsl:element name="li">
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

</xsl:stylesheet>
  

Результат такой:

 <newdoc xmlns="http://www/w3.org/1999/xhtml">
  <segment xmlns="" title="Mr. Title">
    <h2>Mr. Title</h2>
    <p>This is one paragraph.
    </p>
    <p>Another paragraph.
    </p>

      <ol>
        <li>
          <p>An item paragraph.</p>

        </li>
        <li>
          <p>Another item paragraph</p>
        </li>
      </ol>

  </segment>    
</newdoc>
  

Бонус: я также хотел бы избавиться от пустых строк и исправить странное форматирование, вызванное удалением узла списка с

  <xsl:template match="foo:list">
  <xsl:apply-templates/>
 </xsl:template>
  

итак, если кто-нибудь знает лучший способ удаления узла, я хотел бы это услышать.

Большое спасибо!

Ответ №1:

Просто добавьте более конкретное правило для абзацев, которые являются дочерними элементами списков:

 <xsl:template match="foo:item/foo:paragraph">
  <xsl:apply-templates/>
</xsl:template>
  

То же самое относится и к вашему дополнительному вопросу, если я правильно понимаю вопрос: не копируйте текстовые узлы с чистыми пробелами, которые являются дочерними элементами элементов списка.

 <xsl:template match="foo:item/text()[normalize-space(.)='']" />
  

Комментарии:

1. Я ценю помощь, но я не могу заставить ни один из них работать. Я заменил свой шаблон match =»foo:list» на эту строку, и <список> снова появляется в выходных данных. Я также надеялся скопировать содержимое абзаца в <li> . И match=»foo: list / foo: paragraph», похоже, по какой-то причине ничего не находит / не делает.

2. Пожалуйста, не заменяйте ни один из ваших существующих кодов, просто добавьте новые правила.

3. Ну ладно! Тогда строка с нормализованным пробелом удаляет лишнюю строку. Замечательно. Хотя это не исправляет отступ — есть ли лучший способ удалить элемент, чем то, что я сделал? И match=»foo: item/ foo:paragraph» теперь находит узел, мне просто нужно было изменить list на item. Спасибо!!

4. Если вы не хотите, чтобы текстовые узлы с пробелами копировались в ваш вывод, вы должны явно отфильтровать их, так же, как последний фрагмент делает для тех, кто находится непосредственно внутри foo:item .

Ответ №2:

Эта таблица стилей:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:foo="http://www.foo.org"
 xmlns="http://www/w3.org/1999/xhtml"
 exclude-result-prefixes="foo">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:preserve-space elements="foo:paragraph"/>
    <xsl:template match="foo:doc">
        <newdoc>
            <xsl:apply-templates/>
        </newdoc>
    </xsl:template>
    <xsl:template match="foo:div">
        <segment title="{foo:title}">
            <xsl:apply-templates/>
        </segment>
    </xsl:template>
    <xsl:template match="foo:title">
        <h2>
            <xsl:apply-templates/>
        </h2>
    </xsl:template>
    <xsl:template match="foo:paragraph">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>
    <xsl:template match="foo:orderedlist">
        <ol>
            <xsl:apply-templates/>
        </ol>
    </xsl:template>
    <xsl:template match="foo:item">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
    <xsl:template match="foo:item/foo:paragraph">
        <xsl:apply-templates/>
    </xsl:template>
</xsl:stylesheet>
  

Вывод:

 <newdoc xmlns="http://www/w3.org/1999/xhtml">
   <segment title="Mr. Title">
      <h2>Mr. Title</h2>
      <p>This is one paragraph.     </p>
      <p>Another paragraph.     </p>
      <ol>
         <li>An item paragraph.</li>
         <li>Another item paragraph</li>
      </ol>
   </segment>
</newdoc>
  

Примечание: В настоящее время ваша таблица стилей представляет собой беспорядок пространств имен. Используйте @exclude-result-prefixes . Исправьте пробелы только в текстовых узлах через объявления xsl:strip-space и xsl:preserve-space .