xml - 使用 XSL 转换(XML 到 XML)包装多个列表元素序列

标签 xml xslt transformation

我有一些输入长(大约 3k 行)的 XML 文档,通常看起来像:

<chapter someAttributes="someValues">
    <title>someTitle</title>

    <p>multiple paragraphs</p>
    <p>...</p>

    <li>
        <p>- some text</p>
    </li>
    <li>
        <p>- some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <li>
        <p>1. some text</p>
    </li>
    <li>
        <p>2. some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <!-- there are other elements such as table, illustration, ul etc. -->  
</chapter>

我想要的是用 olul 元素取决于某些语义并返回包装的 XML。

  • 如果段落中的第一个字符等于-,那么它应该是带有mark="DASH"属性的ul
  • 如果段落以 1.2.3. 等开头,那么我想要 ol numeration="阿拉伯语"

例如(这只是一个序列):

<ul mark="DASH">
    <li>
        <p> some text</p>
    </li>
    <li>
        <p> some other text</p>
    </li>
<ul>

正如您进一步看到的,我需要从所有段落中剪切“标记字符”,即-1.2., 3.

该输入 XML 比我描述的更复杂(嵌套序列、表元素中的内部序列),但我正在寻找一些想法,尤其是如何捕获和处理具有这种语义的特定序列。

我希望输出 XML 具有完全相同的顺序,只是带有包装的 li 元素。如果需要,可提供 XSLT 2.0/EXSLT。

最佳答案

这是一个 XSLT 2.0 样式表:

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

  <xsl:output indent="yes"/>

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

  <xsl:template match="chapter">
    <xsl:copy>
      <xsl:for-each-group select="*" group-adjacent="boolean(self::li)">
        <xsl:choose>
          <xsl:when test="current-grouping-key() and ./p[1][starts-with(., '-')]">
            <ul mark="DASH">
              <xsl:apply-templates select="current-group()"/>
            </ul>
          </xsl:when>
          <xsl:when test="current-grouping-key() and ./p[1][matches(., '[0-9]\.')]">
            <ol numeration="arabic">
              <xsl:apply-templates select="current-group()"/>
            </ol>
          </xsl:when>
          <xsl:otherwise>
            <xsl:copy-of select="current-group()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="li/p/text()[1]">
    <xsl:value-of select="replace(., '^(-|[0-9]\.)', '')"/>
  </xsl:template>

</xsl:stylesheet>

当我将 Saxon 9.3 与该样式表和示例输入一起使用时

<chapter someAttributes="someValues">
    <title>someTitle</title>

    <p>multiple paragraphs</p>
    <p>...</p>

    <li>
        <p>- some text</p>
    </li>
    <li>
        <p>- some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <li>
        <p>1. some text</p>
    </li>
    <li>
        <p>2. some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <!-- there are other elements such as table, illustration, ul etc. -->  
</chapter>

我得到以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<chapter>
   <title>someTitle</title>
   <p>multiple paragraphs</p>
   <p>...</p>
   <ul mark="DASH">
      <li>
        <p> some text</p>
      </li>
      <li>
        <p> some other text</p>
      </li>
   </ul>
   <p>multiple other paragraphs</p>
   <p>...</p>
   <ol numeration="arabic">
      <li>
        <p> some text</p>
      </li>
      <li>
        <p> some other text</p>
      </li>
   </ol>
   <p>multiple other paragraphs</p>
   <p>...</p>
</chapter>

关于xml - 使用 XSL 转换(XML 到 XML)包装多个列表元素序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6234913/

相关文章:

java - sun.org.mozilla.javascript.internal.EcmaError : ReferenceError

php - 在 PHP 中使用 XPath 提取 XML

java - 如何使用 dom 解析器在 xml 中写入特殊字符( &、<、> 等)

xslt - 如何按原样复制所有内容并仅删除特定元素

azure - 使用自定义 .NET 事件合并 Azure 数据工厂中的两个 CSV 文件

java - 如何使用 XLS 转换复制 XML 节点并粘贴到同一级别

python - 如何在 python 中覆盖 XML 属性值而不读取整个文件

php - 如何使用 XSLT 创建 PHP/JSP/ERB 标签?

java - 如何支持在 ExtensionFunction Saxon HE 9.7 中返回 ArrayList

macos - "Fold"使用 CoreAnimation 的 NSWindow