XSLT合并节点

3

我有一个凌乱的xhtml文件,想要将其转换为xml。它是一个带有大量“p”标签的词典,我想对它们进行分类。以下是xhtml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta content="2018-06-29T10:12:48Z" name="dcterms.created" />
        <meta content="2018-06-29T10:12:48Z" name="dcterms.modified" />
    </head>
    <body>
        <p><b>Aesthetik</b></p>
        <p>text about aesthetics.</p>
        <p><b>Expl: </b>explanation about aesthetics</p>
        <p><b>BegrG: </b>origin of the term</p>
        <p>more origin of the term</p>
        <p><b>Allegorese</b></p>
        <p>text about Allegorese</p>
        <p><b>Expl: </b>explanation about Allegorese</p>
        <p><b>BegrG: </b>origin of Allegorese</p>
    </body>
</html>

XSLT文件的格式如下(这里还有其他标签的几行,未在此处包含):

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

<xsl:template match="head"/>

<xsl:template match="text()">
    <xsl:value-of select="normalize-space()"/>
</xsl:template>

<xsl:template match="body">
    <lexica>
        <xsl:apply-templates/>      <!-- create root node lexica -->
    </lexica>
</xsl:template>

<xsl:template match="p">
    <p>
        <xsl:apply-templates/> <!-- copy same tags for better visuality -->
    </p>
</xsl:template>

<xsl:template match="p[b[contains(., 'BegrG')]]">
    <BegrG>
        <xsl:apply-templates/>  <!-- create specific nodes with origin explanation of the word -->
    </BegrG>
</xsl:template>

<xsl:template match="p[b[contains(., 'Expl')]]">
    <Expl>
        <xsl:apply-templates/>  <!-- node with explanation of the word --> 
    </Expl>
</xsl:template>


<xsl:template
    match="
    p[b[not(self::*[contains(., 'Expl')]or
    self::*[contains(., 'BegrG')])]]">  <!-- any other b nodes which are left are lexical items -->
    <Artikel>
        <xsl:apply-templates/>
    </Artikel>
</xsl:template>

最终我的XML文件看起来像这样:
    <lexica>
    <Artikel>Aesthetik</Artikel>
    <p>text about aesthetics.</p>
    <Expl>Expl:explanation about aesthetics</Expl>
    <BegrG>BegrG:origin of the term</BegrG>
    <p>more origin of the term</p>
    <Artikel>Allegorese</Artikel>
    <p>text about Allegorese</p>
    <Expl>Expl:explanation about Allegorese</Expl>
    <BegrG>BegrG:origin of Allegorese</BegrG>
</lexica>

这种排版看起来更好,但仍然无法正常工作,因为它的结构不够严谨。例如,术语没有分组,并且一些“p”标记应该与它们的前一个同级元素合并。它应该是这样的:

<lexica>
 <item>
  <Artikel>Aesthetik</Artikel>
  <short>text about aesthetics.</short>
  <Expl>Expl:explanation about aesthetics</Expl>
  <BegrG>BegrG:origin of the term. more origin of the term.</BegrG>
 </item>

 <item>
  <Artikel>Allegorese</Artikel>
  <short>text about Allegorese</short>
  <Expl>Expl:explanation about Allegorese</Expl>
  <BegrG>BegrG:origin of Allegorese</BegrG>
 </item>
</lexica>

我是不是在错误地接近这个问题,或者我应该如何将具有b-子元素的'p'标签分组到它们的兄弟标签中?并且我如何将术语项彼此分开,并使其能够识别何时出现结束标签?

(对于我的糟糕英语表示抱歉)

提前感谢!


那么你想说的是“这是一个带有许多'a'标签的词典”吗?但是在你展示的样本中,我并没有看到任何a元素或标签。如果你想要分组,你如何确定一个组,结果中的item从输入样本的哪里开始? - Martin Honnen
抱歉,那是个打错了字。我指的是 p 标签而不是 a 标签。 要识别一个组,它会以 p/b(不是“Expl”或“BegrG”)开头,并在出现新的 p/b(不是“Expl”或“BegrG”)时结束。但我不知道该怎么做。 - Sergej Petkau
1个回答

2

XSLT 2/3拥有for-each-group group-starting-withhttps://www.w3.org/TR/xslt20/#xsl-for-each-group),因此您可以使用它来实现创建带有item元素的功能。

  <xsl:template match="body">
      <lexica>
          <xsl:for-each-group select="*" group-starting-with="p[b[not(matches(., '^(Expl|BegrG):'))]]">
              <item>
                  <xsl:apply-templates select="current-group()"/>
              </item>
          </xsl:for-each-group>
      </lexica>
  </xsl:template>

我认为,示例在https://xsltfiddle.liberty-development.net/bFDb2CG

到目前为止,我不确定是什么决定了一些p元素合并到BegrG结果中,也许是嵌套分组。

  <xsl:template match="body">
      <lexica>
          <xsl:for-each-group select="*" group-starting-with="p[b[not(matches(., '^(Expl|BegrG):'))]]">
              <item>
                  <xsl:for-each-group select="current-group()" group-starting-with="p[b[starts-with(., 'BegrG:')]]">
                      <xsl:choose>
                          <xsl:when test="self::p[b[starts-with(., 'BegrG:')]]">
                              <BegrG>
                                  <xsl:apply-templates select="current-group()/node()"/>
                              </BegrG>
                          </xsl:when>
                          <xsl:otherwise>
                              <xsl:apply-templates select="current-group()"/>
                          </xsl:otherwise>
                      </xsl:choose>
                  </xsl:for-each-group>
              </item>
          </xsl:for-each-group>
      </lexica>
  </xsl:template>

实现方式如下:https://xsltfiddle.liberty-development.net/bFDb2CG/1

对于评论中提出的问题,您可以在group-starting-with中添加另一个匹配项:

  <xsl:template match="body">
      <lexica>
          <xsl:for-each-group select="*" group-starting-with="p[b[not(matches(., '^(Expl|BegrG):'))]]">
              <item>
                  <xsl:for-each-group select="current-group()" group-starting-with="p[b[starts-with(., 'Expl:')]] | p[b[starts-with(., 'BegrG:')]]">
                      <xsl:choose>
                        <xsl:when test="self::p[b[starts-with(., 'Expl:')]]">
                              <Expl>
                                  <xsl:apply-templates select="current-group()/node()"/>
                              </Expl>
                          </xsl:when>
                          <xsl:when test="self::p[b[starts-with(., 'BegrG:')]]">
                              <BegrG>
                                  <xsl:apply-templates select="current-group()/node()"/>
                              </BegrG>
                          </xsl:when>
                          <xsl:otherwise>
                              <xsl:apply-templates select="current-group()"/>
                          </xsl:otherwise>
                      </xsl:choose>
                  </xsl:for-each-group>
              </item>
          </xsl:for-each-group>
      </lexica>
  </xsl:template>

https://xsltfiddle.liberty-development.net/bFDb2CG/2


它已经接近了,但是它没将我的所有p标签合并。在我的大文件中,例如/p/b(Expl: )同级之后会有多个p标签。很难为我解释,但是我在这里又做了一个例子: https://xsltfiddle.liberty-development.net/jyH9rMS - Sergej Petkau
1
@SergejPetkau,我已经添加了另一个示例来解决这个问题,如果你还有问题,请尝试嵌套更多的“for-each-group”或添加更多的模式,如果你无法自行解决它,请提出一个新问题,并提供所有必要的细节。 - Martin Honnen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接