我们如何识别一组节点并将该组添加到另一个 XSLT 中 XML 源结构不同的节点?
How do we identify a set of nodes and add that set into another where the structure of XML source vary in XSLT?
我正在尝试将基于 Flash 的文本格式转换为基于 HTML 的文本。
源中有 <LI></LI>
块 xml 我需要在 <ul>
块内添加相邻的 <LI>
块。
<p></p>
<li></li> ------
<li></li> | - should be wrapped with <ul> tag
<li></li> ------
<p></p>
<li></li>
<li></li>
<li></li>
<p></p>
XML 来源
<root>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
edfg
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
sdgfdsgsds
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
sdfgdsg
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
dsgdfgdsfg
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">errytrtyr</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
sdgfdsgsds
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="System" SIZE="16" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="System" SIZE="16" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">
<B>hgjgj</B>
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="CENTER">
<FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">centered text</FONT>
</P>
</TEXTFORMAT>
</root>
预期输出
<div>
<div style="text-align:LEFT; ">
edfg
</div>
<div style="text-align:LEFT; ">
sdgfdsgsds
</div>
<ul>
<li>
sdfgdsg
</li>
<li>
dsgdfgdsfg
</li>
<li>
<FONT COLOR="#4B4B4B" FACE="Lato" SIZE="12">errytrtyr</FONT>
</li>
</ul>
<div style="text-align:LEFT; ">
sdgfdsgsds
</div>
<ul>
<li>
<FONT COLOR="#4B4B4B" FACE="System" SIZE="16">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</li>
<li>
<FONT COLOR="#4B4B4B" FACE="System" SIZE="16">
<B>hgjgj</B>
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</li>
</ul>
<div style="text-align:CENTER; ">
<FONT COLOR="#4B4B4B" FACE="Lato" SIZE="12">centered text</FONT>
</div>
</div>
我的代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="html"/>
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- remove unwanted attributes -->
<xsl:template match="@LETTERSPACING|@KERNING"/>
<!-- Remove <P> tag and set the alignment -->
<xsl:template match="P">
<div>
<xsl:attribute name="style">
<!-- collect attributes -->
<xsl:variable name="styles">
<xsl:if test="@ALIGN">
<xsl:value-of select="concat('text-align:', @ALIGN )"/>
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:variable>
<!-- delete trailing spaces -->
<xsl:value-of select="$styles"/>
</xsl:attribute>
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- Replace <LI> with <li> -->
<xsl:template match="LI">
<li><xsl:apply-templates/></li>
</xsl:template>
<!-- Remove TEXTFORMAT -->
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
这种类型的分组在 XSLT 1.0 中有些困难。
如果可以假定每个 LI 组前面都有一个 P,并且 root
元素内没有其他类型的节点,那么您可以这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="LI" match="TEXTFORMAT[LI]" use="generate-id(preceding-sibling::TEXTFORMAT[P][1])" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates select="TEXTFORMAT[P]"/>
</div>
</xsl:template>
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="P">
<div style="text-align:{@ALIGN};">
<xsl:apply-templates/>
</div>
<xsl:variable name="li" select="key('LI', generate-id(..))" />
<xsl:if test="$li">
<ul>
<xsl:apply-templates select="$li"/>
</ul>
</xsl:if>
</xsl:template>
<xsl:template match="LI">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
<xsl:template match="@LETTERSPACING|@KERNING"/>
</xsl:stylesheet>
以下 XSLT 1.0 转换为您提供了您想要的结果:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="html"/>
<xsl:key name="list" match="TEXTFORMAT[LI]" use="generate-id(
(self::*|preceding-sibling::*)[LI][
not(preceding-sibling::*[1][LI])
][last()]
)" />
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates />
</div>
</xsl:template>
<!-- Remove <P> tag and set the alignment -->
<xsl:template match="P">
<div>
<xsl:attribute name="style">
<xsl:apply-templates select="@*" mode="css" />
</xsl:attribute>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="@ALIGN" mode="css">
<xsl:value-of select="concat('text-align:', ., ';')"/>
</xsl:template>
<!-- add more -->
<xsl:template match="@*" mode="css" />
<!-- remove unwanted attributes -->
<xsl:template match="@LETTERSPACING|@KERNING"/>
<xsl:template match="TEXTFORMAT[LI]">
<xsl:variable name="adjacent" select="key('list', generate-id())" />
<xsl:if test="$adjacent">
<ul>
<xsl:apply-templates select="$adjacent/LI" />
</ul>
</xsl:if>
</xsl:template>
<!-- Replace <LI> with <li> -->
<xsl:template match="LI">
<li><xsl:apply-templates/></li>
</xsl:template>
<!-- Remove TEXTFORMAT -->
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
结果:
<div>
<div style="text-align:LEFT;">
edfg
</div>
<div style="text-align:LEFT;">
sdgfdsgsds
</div>
<ul>
<li>
sdfgdsg
</li>
<li>
dsgdfgdsfg
</li>
<li><FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B">errytrtyr</FONT></li>
</ul>
<div style="text-align:LEFT;">
sdgfdsgsds
</div>
<ul>
<li><FONT FACE="System" SIZE="16" COLOR="#4B4B4B">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT></FONT></li>
<li><FONT FACE="System" SIZE="16" COLOR="#4B4B4B"><B>hgjgj</B><FONT FACE="Lato" SIZE="12"></FONT></FONT></li>
</ul>
<div style="text-align:CENTER;"><FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B">centered text</FONT></div>
</div>
从字面上看,解决方案的关键是这个结构:
<xsl:key name="list" match="TEXTFORMAT[LI]" use="generate-id(
(self::*|preceding-sibling::*)[LI][
not(preceding-sibling::*[1][LI])
][last()]
)" />
这通过开始当前系列的最近 TEXTFORMAT[LI]
的唯一 ID 为文档中的每个 TEXTFORMAT[LI]
编制索引,即最近的没有 TEXTFORMAT[LI]
的 ID。
从那里我们可以在 <xsl:template match="TEXTFORMAT[LI]">
中决定是否为任何给定的 TEXTFORMAT[LI]
.
输出一些东西
我正在尝试将基于 Flash 的文本格式转换为基于 HTML 的文本。
源中有 <LI></LI>
块 xml 我需要在 <ul>
块内添加相邻的 <LI>
块。
<p></p>
<li></li> ------
<li></li> | - should be wrapped with <ul> tag
<li></li> ------
<p></p>
<li></li>
<li></li>
<li></li>
<p></p>
XML 来源
<root>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
edfg
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
sdgfdsgsds
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
sdfgdsg
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
dsgdfgdsfg
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">errytrtyr</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="LEFT">
sdgfdsgsds
</P>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="System" SIZE="16" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<LI>
<FONT FACE="System" SIZE="16" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">
<B>hgjgj</B>
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</LI>
</TEXTFORMAT>
<TEXTFORMAT LEADING="2">
<P ALIGN="CENTER">
<FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B" LETTERSPACING="0" KERNING="0">centered text</FONT>
</P>
</TEXTFORMAT>
</root>
预期输出
<div>
<div style="text-align:LEFT; ">
edfg
</div>
<div style="text-align:LEFT; ">
sdgfdsgsds
</div>
<ul>
<li>
sdfgdsg
</li>
<li>
dsgdfgdsfg
</li>
<li>
<FONT COLOR="#4B4B4B" FACE="Lato" SIZE="12">errytrtyr</FONT>
</li>
</ul>
<div style="text-align:LEFT; ">
sdgfdsgsds
</div>
<ul>
<li>
<FONT COLOR="#4B4B4B" FACE="System" SIZE="16">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</li>
<li>
<FONT COLOR="#4B4B4B" FACE="System" SIZE="16">
<B>hgjgj</B>
<FONT FACE="Lato" SIZE="12"></FONT>
</FONT>
</li>
</ul>
<div style="text-align:CENTER; ">
<FONT COLOR="#4B4B4B" FACE="Lato" SIZE="12">centered text</FONT>
</div>
</div>
我的代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="html"/>
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- remove unwanted attributes -->
<xsl:template match="@LETTERSPACING|@KERNING"/>
<!-- Remove <P> tag and set the alignment -->
<xsl:template match="P">
<div>
<xsl:attribute name="style">
<!-- collect attributes -->
<xsl:variable name="styles">
<xsl:if test="@ALIGN">
<xsl:value-of select="concat('text-align:', @ALIGN )"/>
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:variable>
<!-- delete trailing spaces -->
<xsl:value-of select="$styles"/>
</xsl:attribute>
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- Replace <LI> with <li> -->
<xsl:template match="LI">
<li><xsl:apply-templates/></li>
</xsl:template>
<!-- Remove TEXTFORMAT -->
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
这种类型的分组在 XSLT 1.0 中有些困难。
如果可以假定每个 LI 组前面都有一个 P,并且 root
元素内没有其他类型的节点,那么您可以这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="LI" match="TEXTFORMAT[LI]" use="generate-id(preceding-sibling::TEXTFORMAT[P][1])" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates select="TEXTFORMAT[P]"/>
</div>
</xsl:template>
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="P">
<div style="text-align:{@ALIGN};">
<xsl:apply-templates/>
</div>
<xsl:variable name="li" select="key('LI', generate-id(..))" />
<xsl:if test="$li">
<ul>
<xsl:apply-templates select="$li"/>
</ul>
</xsl:if>
</xsl:template>
<xsl:template match="LI">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
<xsl:template match="@LETTERSPACING|@KERNING"/>
</xsl:stylesheet>
以下 XSLT 1.0 转换为您提供了您想要的结果:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="html"/>
<xsl:key name="list" match="TEXTFORMAT[LI]" use="generate-id(
(self::*|preceding-sibling::*)[LI][
not(preceding-sibling::*[1][LI])
][last()]
)" />
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<div>
<xsl:apply-templates />
</div>
</xsl:template>
<!-- Remove <P> tag and set the alignment -->
<xsl:template match="P">
<div>
<xsl:attribute name="style">
<xsl:apply-templates select="@*" mode="css" />
</xsl:attribute>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="@ALIGN" mode="css">
<xsl:value-of select="concat('text-align:', ., ';')"/>
</xsl:template>
<!-- add more -->
<xsl:template match="@*" mode="css" />
<!-- remove unwanted attributes -->
<xsl:template match="@LETTERSPACING|@KERNING"/>
<xsl:template match="TEXTFORMAT[LI]">
<xsl:variable name="adjacent" select="key('list', generate-id())" />
<xsl:if test="$adjacent">
<ul>
<xsl:apply-templates select="$adjacent/LI" />
</ul>
</xsl:if>
</xsl:template>
<!-- Replace <LI> with <li> -->
<xsl:template match="LI">
<li><xsl:apply-templates/></li>
</xsl:template>
<!-- Remove TEXTFORMAT -->
<xsl:template match="TEXTFORMAT">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
结果:
<div>
<div style="text-align:LEFT;">
edfg
</div>
<div style="text-align:LEFT;">
sdgfdsgsds
</div>
<ul>
<li>
sdfgdsg
</li>
<li>
dsgdfgdsfg
</li>
<li><FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B">errytrtyr</FONT></li>
</ul>
<div style="text-align:LEFT;">
sdgfdsgsds
</div>
<ul>
<li><FONT FACE="System" SIZE="16" COLOR="#4B4B4B">nm,hjku
<FONT FACE="Lato" SIZE="12"></FONT></FONT></li>
<li><FONT FACE="System" SIZE="16" COLOR="#4B4B4B"><B>hgjgj</B><FONT FACE="Lato" SIZE="12"></FONT></FONT></li>
</ul>
<div style="text-align:CENTER;"><FONT FACE="Lato" SIZE="12" COLOR="#4B4B4B">centered text</FONT></div>
</div>
从字面上看,解决方案的关键是这个结构:
<xsl:key name="list" match="TEXTFORMAT[LI]" use="generate-id(
(self::*|preceding-sibling::*)[LI][
not(preceding-sibling::*[1][LI])
][last()]
)" />
这通过开始当前系列的最近 TEXTFORMAT[LI]
的唯一 ID 为文档中的每个 TEXTFORMAT[LI]
编制索引,即最近的没有 TEXTFORMAT[LI]
的 ID。
从那里我们可以在 <xsl:template match="TEXTFORMAT[LI]">
中决定是否为任何给定的 TEXTFORMAT[LI]
.