我正在尝试进行身份转换。这是我的源xml的示例:
<?xml version="1.0" encoding="UTF-8"?>
<text>
<p id="542">This is a parapgraph</p>
<p id="561">This is a first level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="542">This is a parapgraph</p>
<p id="561">This is a first level bullet</p>
<p id="562">This is a second level bullet</p>
<p id="562">This is a second level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="561">This is a first level bullet</p>
<p id="542">This is a parapgraph</p>
<p id="542">This is a parapgraph</p>
<p id="560">This is a first ordered list</p>
<p id="560">This is a first ordered list</p>
<p id="560">This is a first ordered list</p>
<p id="562">This is a second level bullet</p>
<p id="562">This is a second level bullet</p>
</text>enter code here
我正在寻找类似于以下内容的输出:
<?xml version="1.0" encoding="UTF-8"?>
<text>
<p id="">This is a parapgraph</p>
<ul>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p id="">This is a parapgraph</p>
<ul>
<li>This is a first level bullet
<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul></li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p id="">This is a parapgraph</p>
<p id="">This is a parapgraph</p>
<ol>
<li>This is a first ordered list</li>
<li>This is a first ordered list</li>
<li>This is a first ordered list</li>
<li>This is a first level bullet
<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul>
</li>
<li>This is a first level bullet</li>
</ol>
</text>
能否请您帮我了解该怎么做?我是XSLT的新手。我正在寻找一种执行类似操作但找不到的教程。 我当前的XSLT如下所示:
<?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" standalone="no"/>
<xsl:template match="/">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="topic">
<book>
<xsl:attribute name="id">
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</book>
</xsl:template>
<xsl:template match="body">
<text>
<xsl:apply-templates select="p[@id='542']"/>
<xsl:call-template name="f-ul"/>
<xsl:call-template name="s-ul"/>
<xsl:call-template name="o-l"/>
</text>
</xsl:template>
<!-- all body text style to p tag> -->
<xsl:template match="p[@id='542']">
<p><xsl:apply-templates select="@*|node()" /></p>
</xsl:template>
<xsl:template name="f-ul">
<xsl:if test="p[@id='561']">
<ul>
<xsl:attribute name="id">
<xsl:text></xsl:text>
</xsl:attribute>
<xsl:apply-templates select="p[@id='561']"/>
</ul>
</xsl:if>
</xsl:template>
<xsl:template name="s-ul">
<xsl:if test="p[@id='562']">
<ul>
<xsl:attribute name="id">
<xsl:text></xsl:text>
</xsl:attribute>
<xsl:apply-templates select="p[@id='562']"/>
</ul>
</xsl:if>
</xsl:template>
<xsl:template name="o-l">
<xsl:if test="p[@id='560']">
<ol>
<xsl:attribute name="id">
<xsl:text></xsl:text>
</xsl:attribute>
<xsl:apply-templates select="p[@id='560']"/>
</ol>
</xsl:if>
</xsl:template>
<!-- all list number style to step tag> -->
<xsl:template match="p[@id='560']">
<li><xsl:apply-templates select="@*|node()" /></li>
</xsl:template>
<!-- all list bullet style to li tag> -->
<xsl:template match="p[@id='561']">
<li><xsl:apply-templates select="node()" /></li>
</xsl:template>
<!-- all list bullet 2 style to li tag> -->
<xsl:template match="p[@id='562']">
<li><xsl:apply-templates select="node()" /></li>
</xsl:template>
</xsl:stylesheet>
如果您可以帮助我找到解决方案,或者至少将我定向到正确的资源,将不胜感激。谢谢大家。
答案 0 :(得分:1)
总是很难从示例中进行操作,并且我不确定所显示的所需结果是否一致,我建议进行两步转换,第一个确定li项并设置ol/ul
,第二个确定任何内部列表都包裹在前面的li
中。
这是第一步的XSLT 3方法(适用于Java和.NET的Saxon 9.8或9.9,以及oXygen或Stylus Studio等XML IDE中也由Altova Raptor在其产品线中实现的自2017年发行以来))第一步:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="list-levels" as="map(xs:integer, xs:integer+)"
select="map { 1 : (560, 561), 2: (562) }"/>
<xsl:param name="list-map" as="map(xs:integer, xs:QName)"
select="map { 560 : QName('', 'ol'), 561 : QName('', 'ul'), 562 : QName('', 'ul') }"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="nodes" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$nodes" group-adjacent="boolean(self::p[@id = $list-levels?($level to 6)])">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="{$list-map(xs:integer(@id))}">
<xsl:sequence select="mf:group(current-group(), $level + 1)"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="text">
<xsl:copy>
<xsl:sequence select="mf:group(*, 1)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[@id = 542]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[@id = $list-levels?*]">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
</xsl:stylesheet>
您可以将其设置为在https://xsltfiddle.liberty-development.net/pPzifoZ上运行,结果如下:
<text>
<p>This is a parapgraph</p>
<ul>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p>This is a parapgraph</p>
<ul>
<li>This is a first level bullet</li>
<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p>This is a parapgraph</p>
<p>This is a parapgraph</p>
<ol>
<li>This is a first ordered list</li>
<li>This is a first ordered list</li>
<li>This is a first ordered list</li>
<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul>
</ol>
</text>
第二步,我添加了处理嵌套ul
或ol
的包装的模式:
<xsl:mode name="wrap" on-no-match="shallow-copy"/>
<xsl:template match="ul | ol" mode="wrap">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="li">
<xsl:copy>
<xsl:apply-templates select="node(), current-group() except ." mode="#current"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="mf:group(*, 1)" mode="wrap"/>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/pPzifoZ/1处的示例产生输出
<text>
<p>This is a parapgraph</p>
<ul>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p>This is a parapgraph</p>
<ul>
<li>This is a first level bullet<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul>
</li>
<li>This is a first level bullet</li>
<li>This is a first level bullet</li>
</ul>
<p>This is a parapgraph</p>
<p>This is a parapgraph</p>
<ol>
<li>This is a first ordered list</li>
<li>This is a first ordered list</li>
<li>This is a first ordered list<ul>
<li>This is a second level bullet</li>
<li>This is a second level bullet</li>
</ul>
</li>
</ol>
</text>
完整代码是
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="list-levels" as="map(xs:integer, xs:integer+)"
select="map { 1 : (560, 561), 2: (562) }"/>
<xsl:param name="list-map" as="map(xs:integer, xs:QName)"
select="map { 560 : QName('', 'ol'), 561 : QName('', 'ul'), 562 : QName('', 'ul') }"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="nodes" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$nodes" group-adjacent="boolean(self::p[@id = $list-levels?($level to 6)])">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="{$list-map(xs:integer(@id))}">
<xsl:sequence select="mf:group(current-group(), $level + 1)"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:mode name="wrap" on-no-match="shallow-copy"/>
<xsl:template match="ul | ol" mode="wrap">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="li">
<xsl:copy>
<xsl:apply-templates select="node(), current-group() except ." mode="#current"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="mf:group(*, 1)" mode="wrap"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[@id = 542]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[@id = $list-levels?*]">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
</xsl:stylesheet>
示例使用XSLT 3,但是分组在XSLT 2中将是相同的,只需要将p
id到元素和列表级别的映射存储在某种XML结构而不是XPath {{1 }} s我在上面使用过。
限制:在map
中,我选择了最大嵌套级别6,但是可以很容易地对其进行调整。
但是,选择一些更智能的表示形式(如数组)将使我们避免定义最高级别,因此,像https://xsltfiddle.liberty-development.net/pPzifoZ/2一样,先使用$level to 6
然后使用<xsl:param name="list-levels" as="array(xs:integer+)" select="[ (560, 561), (562) ]"/>
,就没有了需要定义一个硬编码到XSLT中的最高级别。