XSLT - 通过分析文本字符串添加节点

时间:2016-11-08 19:38:16

标签: xml xslt xslt-2.0

我有一个xml文件,在比较两个xml文件之后生成..看起来这个,

<doc>
    <para><change flag="start"/><content>changed text</content><change flag="end"/> para text</para> <!--considerd as a change-->
    <para><change flag="start"/><content>changed <t/>text</content><change flag="end"/> para text</para><!--considerd as a change-->
    <para><change flag="start"/>​<content>(1)</content><change flag="end"/> para text</para><!--not considerd as a change-->
    <para><change flag="start"/>​<content>i.</content><change flag="end"/> para text</para><!--not considerd as a change-->
    <para><change flag="start"/>​<content>•</content><change flag="end"/> para text</para><!--not considerd as a change-->
    <para><change flag="start"/><content>​  </content><change flag="end"/> para text</para><!--not considerd as a change-->
    <para><change flag="start"/><content>(1) this is a <t/> numberd list</content><change flag="end"/> para text</para><!--considerd as a change-->
    <para><change flag="start"/>​<content>• this is a <t/> bullet list</content><change flag="end"/>para text</para><!--considerd as a change-->
</doc>

此处<change>元素显示两个文件的差异,并在<change flag="start"/>​<change flag="end"/>元素之间显示更改的内容。

我的要求是将其转换为html。 <change flag="start"/>​<change flag="end"/>之间的内容(两个xml文件的差异)应该包含<CH>个元素。

<html>
   <head></head>
   <body>
      <p><CH>changed text</CH>para text</p>  
      <p><CH>changed text</CH>para text</p>
      <p>​<CH>(1)</CH>para text</p>
      <p>​<CH>i.</CH>para text</p>
      <p>​<CH>•</CH>para text</p>
      <p><CH>​  </CH>para text</p>
      <p><CH>(1) this is a  numberd list</CH>para text</p>
      <p>​<CH>• this is a  bullet list</CH>para text</p>
   </body>
</html>

但问题是<change flag="start"/>​<change flag="end"/>是为项目符号,列表编号和某些空格添加的。 eventhout这些是在比较html表示的xml文件时的更改,不应将其视为更改。

所以我真实的预期html输出是,

<html>
   <head></head>
   <body>
      <p><CH>changed text</CH> para text</p>  
      <p><CH>changed text</CH> para text</p>
      <p>​(1) para text</p>
      <p>​(a) para text</p>
      <p>​• para text</p>
      <p>​  para text</p>
      <p><CH>(1) this is a  numberd list</CH> para text</p>
      <p>​<CH>• this is a  bullet list</CH> para text</p>
   </body>
</html>

我已编写以下xslt来执行此任务,

<xsl:template match="doc">
        <html>
            <head></head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>


    <xsl:template match="para">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>


    <xsl:template match="*[preceding-sibling::change[@flag='start'] and following-sibling::change[@flag = 'end']]
        [matches(.,$list.mapping/map/@numerator-regex)]">
        <CH>
            <xsl:apply-templates/>
        </CH>
    </xsl:template>


<xsl:variable name="list.mapping" as="element()*">
    <map numerator-regex="^\(\d\)"/>
    <map numerator-regex="^\(\d\d\)"/>
    <map numerator-regex="^\d\)"/>
    <map numerator-regex="^\d\."/>
    <map numerator-regex="^\([A-Za-z]\.\)"/>
    <map numerator-regex="^•"/>
    <map numerator-regex="^*"/>
</xsl:variable>


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

但现在这已经按预期工作了。任何人都可以建议我怎样才能做到这一点,特别是如何消除向以下场景添加标签的方法,

  • 项目符号(•)[项目符号包含<change flag="start"/>​<change flag="end"/>]
  • 列表编号(1),(a)[列表编号包含在<change flag="start"/>​<change flag="end"/>之间]
  • 空格[空格包含在<change flag="start"/>​<change flag="end"/>之间]

1 个答案:

答案 0 :(得分:0)

首先,我认为您需要更改list.mapping变量以包含$符号。 '^'匹配文本的开头,$匹配文本的结尾。这将停止^\(\d\)匹配(1) this is a numberd list

<xsl:variable name="list.mapping" as="element()*">
    <map numerator-regex="^\(\d\)$"/>
    <map numerator-regex="^\(\d\d\)$"/>
    <map numerator-regex="^\d\)$"/>
    <map numerator-regex="^\d\.$"/>
    <map numerator-regex="^\([A-Za-z]\.\)$"/>
    <map numerator-regex="^•$"/>
    <map numerator-regex="^\*$"/>
</xsl:variable>

至于匹配,由于您使用as="element()*",这意味着您应该$list.mapping/@numerator-regex而不是$list.mapping/map/@numerator-regex。您还应检查不匹配的内容。

你想要的条件是......

[not($list.mapping/@numerator-regex[matches(current(), .)])]

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="doc">
        <html>
            <head></head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="para">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template>

    <xsl:template match="*[preceding-sibling::change[@flag='start'] and following-sibling::change[@flag = 'end']]
        [not($list.mapping/@numerator-regex[matches(current(), .)])]">
        <CH>
            <xsl:apply-templates/>
        </CH>
    </xsl:template>

<xsl:variable name="list.mapping" as="element()*">
    <map numerator-regex="^\(\d\)$"/>
    <map numerator-regex="^\(\d\d\)$"/>
    <map numerator-regex="^\d\)$"/>
    <map numerator-regex="^\d\.$"/>
    <map numerator-regex="^\([A-Za-z]\.\)$"/>
    <map numerator-regex="^•$"/>
    <map numerator-regex="^\*$"/>
</xsl:variable>
</xsl:stylesheet>

这可能无法为您提供所需的确切输出,因为您的输入XML可能会有一些影响事物的隐藏unicode字符,但它可能会给您一个开始。