Xml XSLT 2.0用于扁平化和修剪过度<;span>;s 背景

Xml XSLT 2.0用于扁平化和修剪过度<;span>;s 背景,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我们负责处理由我们公司的另一个小组生成的XML文本。有些XML是在Confluence中创建的(对于熟悉它的人来说),有些XML最初是在其他工具(最常见的是MS Word)中编写的,并导入Confluence中 导入的内容在屏幕上看起来不错,但在引擎盖下可能会很难看。为了保持理智,在通过工具链的其余部分运行文件之前,我们对XML进行了一些基于XSLT的预处理 目前我无法轻松应对的一个挑战是跨度过大。在MS Word的创作过程中,文档创建者在不同的时间将颜色应用于不同的部分。Word女士尽职尽责地

我们负责处理由我们公司的另一个小组生成的XML文本。有些XML是在Confluence中创建的(对于熟悉它的人来说),有些XML最初是在其他工具(最常见的是MS Word)中编写的,并导入Confluence中

导入的内容在屏幕上看起来不错,但在引擎盖下可能会很难看。为了保持理智,在通过工具链的其余部分运行文件之前,我们对XML进行了一些基于XSLT的预处理

目前我无法轻松应对的一个挑战是跨度过大。在MS Word的创作过程中,文档创建者在不同的时间将颜色应用于不同的部分。Word女士尽职尽责地维护了文件源中这些更改的历史记录,从未清理过任何东西。导入后,所有这些无关的历史都出现在Confluence XML中,这给我们带来了一些悲伤

源头 这是一个样品。文本和URL已被屏蔽以保护罪犯。:)

目标 我们希望它变成:

<page>
    <p>Mostly black text and more mostly black,<span style="color: rgb(255,0,0);"> followed by red</span>. And this is mostly black again. And <a href="http://example.com/a_page">a link</a> for good measure.<br/></p>
    <p>This is black,<span style="color: rgb(255,0,0);"> this is red</span>. This is black again.<br/></p>
    <p><span style="color: rgb(0,51,102);">Dark blue text with more dark blue after it.</span></p>
    <p><span style="color: rgb(0,51,102);">Dark blue</span><span style="color: rgb(128,51,102);"> and magenta text.</span></p>
    <p><span style="font-weight: bold;"><span style="color: rgb(0,51,102);">Dark blue</span><span style="color: rgb(128,51,102);"> and bold magenta text.</span></span><span style="color: rgb(0,51,102);"> More dark blue.</span></p>
    <p><span style="color: rgb(0,51,102);">Dark blue</span><span style="color: rgb(128,51,102);"> and magenta text.</span></p>
    <p>This is default text, <span style="color: rgb(255,0,0);">with some red </span> and some more embedded "black", and <a href="http://www.example.com/eggplant">a link with <span style="color: rgb(0,0,0);">more inline color formatting</span> for good measure</a>.</p>
    <p><span style="color: rgb(128,51,102);">Magenta on the front. </span><span style="color: rgb(0,51,102);">Dark blue</span><span style="color: rgb(128,51,102);"> and magenta text.</span></p>
    <p><span style="color: rgb(0,51,102);">Dark blue. </span><span style="color: rgb(128,51,102);">Magenta here. </span><span style="color: rgb(0,51,102);">Dark blue</span><span style="color: rgb(128,51,102);"> and magenta text.</span></p>
</page>

大部分是黑色文本,更多的是黑色,然后是红色。这又基本上是黑色的了。为了更好的测量。

这是黑色的,这是红色的。这又是黑色的。

深蓝色文本后面有更多深蓝色

深蓝色和洋红色文本

深蓝色和粗体品红色文本。更多的深蓝色

深蓝色和洋红色文本

这是默认文本,有些是红色,有些是嵌入的“黑色”,还有

正面是洋红色。深蓝色和洋红色文本

深蓝色。这里是洋红色。深蓝色和洋红色文本

嵌套的
标记的深度似乎是任意的。在一个值得注意的例子中,我们看到一个15层深的标记结构。o、 o

到目前为止,我的方法基本上是通过尝试提出尽可能多的不同场景来强行解决问题。多年来,我了解到,暴力强迫通常是我走错方向的一个指标

我花了几天的时间来琢磨这件事,既然我想不出什么

  • 始终涵盖所有基础和工程,以及
  • 可维护且至少有一半优雅

  • 我把这个带到这里是希望从别人的智慧中挖掘出一块金块。

    你可以做的是两次转换。首先,对于每个
    p
    元素,您可以找到所有非span元素,并创建一系列新元素,其中包含作为属性的相关颜色

        <xsl:variable name="text">
            <xsl:for-each select=".//node()[not(self::span)]">
                <xsl:variable name="color" select="ancestor::span[contains(@style, 'color: ')][1]/@style" />
                <text color="{substring-before(substring-after($color, 'color: '), ';')}">
                    <xsl:copy-of select="." />
                </text>
            </xsl:for-each>
        </xsl:variable>
    
    然后,您可以在此
    $text
    变量上使用
    xsl:for each group
    对具有相同
    color
    属性的相邻节点进行分组

    试试这个方法

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
    
        <xsl:template match="p">
            <xsl:variable name="text">
                <xsl:for-each select=".//node()[not(self::span)]">
                    <xsl:variable name="color" select="ancestor::span[contains(@style, 'color: ')][1]/@style" />
                    <text color="{substring-before(substring-after($color, 'color: '), ';')}">
                        <xsl:copy-of select="." />
                    </text>
                </xsl:for-each>
            </xsl:variable>
            <xsl:copy-of select="$text" />
            <p>
                <xsl:for-each-group select="$text/text" group-adjacent="@color">
                    <xsl:choose>
                        <xsl:when test="@color = '' or @color='rgb(51,51,51)'">
                            <xsl:copy-of select="current-group()/node()" />
                        </xsl:when>
                        <xsl:otherwise>
                            <span style="color: {current-grouping-key()};">
                                <xsl:copy-of select="current-group()/node()" />
                            </span>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </p>
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    
    
    
    

    事实上,在写了这篇文章之后,我意识到您实际上可以在一个过程中完成这项工作,而无需首先创建变量

    也试试这个

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
    
        <xsl:template match="p">
            <p>
                <xsl:for-each-group select=".//node()[not(self::span)]" 
                                    group-adjacent="substring-before(substring-after(ancestor::span[contains(@style, 'color: ')][1]/@style, 'color: '), ';')">
                    <xsl:choose>
                        <xsl:when test="current-grouping-key() = '' or current-grouping-key()='rgb(51,51,51)'">
                            <xsl:copy-of select="current-group()" />
                        </xsl:when>
                        <xsl:otherwise>
                            <span style="color: {current-grouping-key()};">
                                <xsl:copy-of select="current-group()/node()" />
                            </span>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </p>
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    
    
    
    


    有趣的方法,谢谢!:)然而,这也有一些缺点。1) 不评估颜色值:我们希望删除所有三个RGB值相同且小于55的
    标记。2) 这是Confluence XML,其中文本可能包含在其他结构中。我使用
    作为示例,只是因为这是手头的文件中的内容;但是,文本也可能在其他内容中,例如
  • ,等等。也就是说,您给了我一些好主意-特别是,您没有匹配
    ,而是匹配其他内容。助教!
    
    <text color="rgb(51,51,51)">Mostly black text </text>
    <text color="rgb(51,51,51)">and more mostly black,</text>
    <text color="rgb(255,0,0)"> followed by red</text>
    <text color="rgb(51,51,51)">. And this is mostly black again. And </text>
    <text color="rgb(51,51,51)"><a href="http://example.com/a_page">a link</a></text>
    <text color="rgb(51,51,51)">a link</text>
    <text color="rgb(51,51,51)"> for good measure.</text>
    <text color="rgb(51,51,51)"><br></text>
    
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
    
        <xsl:template match="p">
            <xsl:variable name="text">
                <xsl:for-each select=".//node()[not(self::span)]">
                    <xsl:variable name="color" select="ancestor::span[contains(@style, 'color: ')][1]/@style" />
                    <text color="{substring-before(substring-after($color, 'color: '), ';')}">
                        <xsl:copy-of select="." />
                    </text>
                </xsl:for-each>
            </xsl:variable>
            <xsl:copy-of select="$text" />
            <p>
                <xsl:for-each-group select="$text/text" group-adjacent="@color">
                    <xsl:choose>
                        <xsl:when test="@color = '' or @color='rgb(51,51,51)'">
                            <xsl:copy-of select="current-group()/node()" />
                        </xsl:when>
                        <xsl:otherwise>
                            <span style="color: {current-grouping-key()};">
                                <xsl:copy-of select="current-group()/node()" />
                            </span>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </p>
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
    
        <xsl:template match="p">
            <p>
                <xsl:for-each-group select=".//node()[not(self::span)]" 
                                    group-adjacent="substring-before(substring-after(ancestor::span[contains(@style, 'color: ')][1]/@style, 'color: '), ';')">
                    <xsl:choose>
                        <xsl:when test="current-grouping-key() = '' or current-grouping-key()='rgb(51,51,51)'">
                            <xsl:copy-of select="current-group()" />
                        </xsl:when>
                        <xsl:otherwise>
                            <span style="color: {current-grouping-key()};">
                                <xsl:copy-of select="current-group()/node()" />
                            </span>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </p>
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>