Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSL合并具有相同类的相同类型的节点_Xml_Xslt_Xslt 2.0 - Fatal编程技术网

Xml XSL合并具有相同类的相同类型的节点

Xml XSL合并具有相同类的相同类型的节点,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我对XSL非常陌生,我正在尝试清理一些XML以合并redondant标记(下面的示例) 我尝试了多种解决方案(使用前一个同级/后一个同级)和下面的XSL 2.0解决方案,但都没有成功 <xsl:template match="p[@class='Normal'][count(./span[@class='USous-article'])>0]"> <xsl:copy> <xsl:for-each-group select="node() except te

我对XSL非常陌生,我正在尝试清理一些XML以合并redondant标记(下面的示例)

我尝试了多种解决方案(使用前一个同级/后一个同级)和下面的XSL 2.0解决方案,但都没有成功

<xsl:template match="p[@class='Normal'][count(./span[@class='USous-article'])>0]">
<xsl:copy>
  <xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="boolean(self::*)">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <xsl:for-each-group select="current-group()" group-by="concat(node-name(.), '|', @class)">
          <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:copy-of select="@class" />
            <xsl:apply-templates select="current-group()/node()" />
          </xsl:element>
        </xsl:for-each-group>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:copy>
</xsl:template>


有什么想法吗?我没有任何线索…

请尝试以下脚本:

<?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" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:preserve-space elements="span"/>

  <xsl:template match="p[@class='Normal']">
    <p>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="*" group-adjacent="concat(name(), '/',  @class)">
        <xsl:element name="{name()}">
          <xsl:attribute name="class" select="@class"/>
          <xsl:value-of select="current-group()/text()"/>
        </xsl:element>
      </xsl:for-each-group>
      <xsl:value-of select="text()"/>
    </p>
  </xsl:template>

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


注意模板匹配
p
中的操作顺序:

  • 复制
    p
    元素
  • 将模板应用于属性
  • 对于具有相同名称和类别的每组相邻节点:
    • 复制元素
    • 复制类属性
  • 复制当前元素的文本
另一个需要注意的要点是
strip space
preserve space
命令:

  • 从所有标记中删除空间
  • 除了要保留空格的
    span
    标记之外

否则最后一个
span
元素的空格内容就会丢失。

当我在一个最简单的例子中尝试您发布的模板时,它似乎合并了
span
shmm,这很奇怪,所以我的问题不是真正的XSL。另一个问题:您知道为什么模板不应用于嵌套的
a
?这是一个链接,当您的代码与父元素
p
匹配时,您不会
apply templates
到嵌套的
a
元素,然后您的分组创建一个新的
a
元素,只需将
apply templates
应用到其子节点。我认为这个问题更难,如果你不能自己调试和解决它,就需要一个新的、单独的问题。这会不会将span前的任何文本移到
p
(合并span后)的末尾?是的,但源示例表明span标记位于开始处,并且只有在它们出现任何“正常”文本之后。
<xsl:template match="p[@class='Normal'][count(./span[@class='USous-article'])>0]">
<xsl:copy>
  <xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="boolean(self::*)">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <xsl:for-each-group select="current-group()" group-by="concat(node-name(.), '|', @class)">
          <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:copy-of select="@class" />
            <xsl:apply-templates select="current-group()/node()" />
          </xsl:element>
        </xsl:for-each-group>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:copy>
</xsl:template>
<?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" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:preserve-space elements="span"/>

  <xsl:template match="p[@class='Normal']">
    <p>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="*" group-adjacent="concat(name(), '/',  @class)">
        <xsl:element name="{name()}">
          <xsl:attribute name="class" select="@class"/>
          <xsl:value-of select="current-group()/text()"/>
        </xsl:element>
      </xsl:for-each-group>
      <xsl:value-of select="text()"/>
    </p>
  </xsl:template>

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