XSLT:如何从复杂生成的 HTML 页面中过滤内容?
XSLT: How to filter content from complex generated HTML pages?
这里可以找到一些很好的示例,说明如何使用 XSLT 过滤和合并简单的 HTML 页面。
有大量单个已保存的 HTML 页面(已使用 ASP 生成),如下例所示,应将其过滤并合并为一个 HTML从中生成一本书。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="../../../../external.html?link=http://www.w3.org/1999/xhtml" >
<head id="Head1"><title>
2021_0623.aspx
</title>
</style></head>
<body>
<div align="center">
<div class="aspNetHidden">
</div>
<table width="95%" id="table1" cellspacing="0" cellpadding="0" border="0" >
<tr>
<td>
</td>
<td width="100%" bgcolor="black" style="padding: 10px;">
<div align="center">
</div>
</td>
</tr>
<tr>
<td>
</td>
<td bgcolor="black" width="100%" height="20px" style="padding-left: 20px; padding-right: 20px; padding-bottom: 10px;">
<div class="align-left">
</div>
</td>
</tr>
<tr>
<td align="right" valign="top" style="padding-right: 10px">
<a href="" /></a><div id="Menu1">
<ul class="level1">
<li>Recent Updates</li>
</ul>
</div><a id="Menu1_SkipLink"></a>
</td>
<td width="100%" valign="top" bgcolor="white" style="padding: 20px;">
<p class="page-title">Library</p>
<p class="page-title-2">Library Text</p>
<div class="nav">
<table class="nav">
<tr class="nav">
<td class="nav-title">Some unneeded navigation</td>
<td class="nav">
</td>
</tr>
</table>
</div>
<p class="copyright">Copyright © 2021</p>
<p class="about"><strong>ABOUT THE CONTENTS.</strong></p>
<p class="text-title">Title of text</p>
<p class="text-date">August 22, 2021</p>
<p>text of interest.</p>
<p>more text of interest.</p>
<p class="separator-left-33"> </p>
<p class="footnote"><a id="_ftn1" href="#_ftnref1" name="_ftn1">[1]</a> a footnote of interest</p>
<p class="footnote"><a id="_ftn2" href="#_ftnref2" name="_ftn1">[2]</a> one more footnote of interest</p>
<div class="nav">
<table class="nav">
</table>
</div>
</td>
</tr>
<tr>
<td>
</td>
<td width="100%" height="45" align="left" valign="top" style="padding-left: 20px; padding-top: 5px;" bgcolor="black">
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
结果应该是过滤掉所有以title开头的内容
<p class="page-title">Library</p>
包括脚注。
XSLT 是否可以做到这一点,也许可以展示实现此目的的方法?
过滤不需要的导航会很好,也许 class="about" 总是一样的。
但这可以在之后分几步完成。
预期的输出应该是这样的,或者可以是格式正确的 HTML-page:
<p class="page-title">Library</p>
<p class="page-title-2">Library Text</p>
<p class="copyright">Copyright © 2021</p>
<p class="text-title">Title of text</p>
<p class="text-date">August 22, 2021</p>
<p>text of interest.</p>
<p>more text of interest.</p>
<p class="separator-left-33"> </p>
<p class="footnote"><a id="_ftn1" href="#_ftnref1" name="_ftn1">[1]</a> a footnote of interest</p>
<p class="footnote"><a id="_ftn2" href="#_ftnref2" name="_ftn1">[2]</a> one more footnote of interest</p>
所以这是执行所需提取的 perl 脚本的基本解决方案:
#!/usr/bin/perl
my $LCount = 0; # Line count
my $ICount = 0; # Line ignore count
my $DCount = 0; # Line done count
my $Line; # actual line
if (@ARGV == 0) { # Kein Paramter -> Beschreibung
print "\n";
print "extract.pl [input-file] [output-file]\n";
print "\n";
exit;
}
if (@ARGV < 1) { die "To less parameter!\n"; }
if (@ARGV > 2) { die "To much parameter!\n"; }
my $InputFile = $ARGV[0];
my $OutputFile = $ARGV[1];
###############################################################################
# Main programm
###############################################################################
open(InFile, $InputFile) or die "Error opening '$InputFile': $!\n";
open(OutFile,"> $OutputFile") or die "Error opening '$OutputFile': $!\n";
while(defined($Line = <InFile>)) {
$LCount ++;
if ($Line =~ /^<p/) {
if ($Line =~ /class=\"about\"/) {
$ICount ++;
} else {
$DCount ++;
print OutFile $Line;
}
} else {
$ICount ++;
}
}
close(InFile) or die "Error closing '$InputFile': $! \n";
close(OutFile) or die "Error closing '$OutputFile': $! \n";
print "\n$LCount lines from $InputFile processed.\n";
print "$DCount lines extracted.\n";
print "$ICount lines ignored.\n\n";
随着一些行的增加,可以过滤掉更多的内容,并且 HTML 框架是可选的。
但如果这可以用 XSLT 类似简单地完成,这仍然很有趣......
在这种特殊情况下,可以使用简单的 grep 在 shell 中完成基本过滤:
grep "<p" 1.html > out.html
首选 perl 解决方案,因为可以实现更多的行为和过滤选项。
xsltproc 似乎有一个选项可以处理 --html
文档而不是 XML 文档,因此假设该选项允许您将输入解析为 HTML 而无需命名空间 XSLT 1 代码
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:variable name="start-element" select="//p[@class = 'page-title']"/>
<xsl:apply-templates select="$start-element | $start-element/following-sibling::p"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果 HTML 文档最终出现在您输入的那个奇数命名空间中,您将必须在 XSLT 1 和 select 中将前缀绑定到该命名空间,并使用 prefix:local-name
例如xhtml:body
或 xhtml:p
其中名称空间声明为 xmlns:xhtml="../../../../external.html?link=http://www.w3.org/1999/xhtml"
.
这里可以找到一些很好的示例,说明如何使用 XSLT 过滤和合并简单的 HTML 页面。
有大量单个已保存的 HTML 页面(已使用 ASP 生成),如下例所示,应将其过滤并合并为一个 HTML从中生成一本书。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="../../../../external.html?link=http://www.w3.org/1999/xhtml" >
<head id="Head1"><title>
2021_0623.aspx
</title>
</style></head>
<body>
<div align="center">
<div class="aspNetHidden">
</div>
<table width="95%" id="table1" cellspacing="0" cellpadding="0" border="0" >
<tr>
<td>
</td>
<td width="100%" bgcolor="black" style="padding: 10px;">
<div align="center">
</div>
</td>
</tr>
<tr>
<td>
</td>
<td bgcolor="black" width="100%" height="20px" style="padding-left: 20px; padding-right: 20px; padding-bottom: 10px;">
<div class="align-left">
</div>
</td>
</tr>
<tr>
<td align="right" valign="top" style="padding-right: 10px">
<a href="" /></a><div id="Menu1">
<ul class="level1">
<li>Recent Updates</li>
</ul>
</div><a id="Menu1_SkipLink"></a>
</td>
<td width="100%" valign="top" bgcolor="white" style="padding: 20px;">
<p class="page-title">Library</p>
<p class="page-title-2">Library Text</p>
<div class="nav">
<table class="nav">
<tr class="nav">
<td class="nav-title">Some unneeded navigation</td>
<td class="nav">
</td>
</tr>
</table>
</div>
<p class="copyright">Copyright © 2021</p>
<p class="about"><strong>ABOUT THE CONTENTS.</strong></p>
<p class="text-title">Title of text</p>
<p class="text-date">August 22, 2021</p>
<p>text of interest.</p>
<p>more text of interest.</p>
<p class="separator-left-33"> </p>
<p class="footnote"><a id="_ftn1" href="#_ftnref1" name="_ftn1">[1]</a> a footnote of interest</p>
<p class="footnote"><a id="_ftn2" href="#_ftnref2" name="_ftn1">[2]</a> one more footnote of interest</p>
<div class="nav">
<table class="nav">
</table>
</div>
</td>
</tr>
<tr>
<td>
</td>
<td width="100%" height="45" align="left" valign="top" style="padding-left: 20px; padding-top: 5px;" bgcolor="black">
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
结果应该是过滤掉所有以title开头的内容
<p class="page-title">Library</p>
包括脚注。
XSLT 是否可以做到这一点,也许可以展示实现此目的的方法?
过滤不需要的导航会很好,也许 class="about" 总是一样的。 但这可以在之后分几步完成。
预期的输出应该是这样的,或者可以是格式正确的 HTML-page:
<p class="page-title">Library</p>
<p class="page-title-2">Library Text</p>
<p class="copyright">Copyright © 2021</p>
<p class="text-title">Title of text</p>
<p class="text-date">August 22, 2021</p>
<p>text of interest.</p>
<p>more text of interest.</p>
<p class="separator-left-33"> </p>
<p class="footnote"><a id="_ftn1" href="#_ftnref1" name="_ftn1">[1]</a> a footnote of interest</p>
<p class="footnote"><a id="_ftn2" href="#_ftnref2" name="_ftn1">[2]</a> one more footnote of interest</p>
所以这是执行所需提取的 perl 脚本的基本解决方案:
#!/usr/bin/perl
my $LCount = 0; # Line count
my $ICount = 0; # Line ignore count
my $DCount = 0; # Line done count
my $Line; # actual line
if (@ARGV == 0) { # Kein Paramter -> Beschreibung
print "\n";
print "extract.pl [input-file] [output-file]\n";
print "\n";
exit;
}
if (@ARGV < 1) { die "To less parameter!\n"; }
if (@ARGV > 2) { die "To much parameter!\n"; }
my $InputFile = $ARGV[0];
my $OutputFile = $ARGV[1];
###############################################################################
# Main programm
###############################################################################
open(InFile, $InputFile) or die "Error opening '$InputFile': $!\n";
open(OutFile,"> $OutputFile") or die "Error opening '$OutputFile': $!\n";
while(defined($Line = <InFile>)) {
$LCount ++;
if ($Line =~ /^<p/) {
if ($Line =~ /class=\"about\"/) {
$ICount ++;
} else {
$DCount ++;
print OutFile $Line;
}
} else {
$ICount ++;
}
}
close(InFile) or die "Error closing '$InputFile': $! \n";
close(OutFile) or die "Error closing '$OutputFile': $! \n";
print "\n$LCount lines from $InputFile processed.\n";
print "$DCount lines extracted.\n";
print "$ICount lines ignored.\n\n";
随着一些行的增加,可以过滤掉更多的内容,并且 HTML 框架是可选的。
但如果这可以用 XSLT 类似简单地完成,这仍然很有趣......
在这种特殊情况下,可以使用简单的 grep 在 shell 中完成基本过滤:
grep "<p" 1.html > out.html
首选 perl 解决方案,因为可以实现更多的行为和过滤选项。
xsltproc 似乎有一个选项可以处理 --html
文档而不是 XML 文档,因此假设该选项允许您将输入解析为 HTML 而无需命名空间 XSLT 1 代码
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:variable name="start-element" select="//p[@class = 'page-title']"/>
<xsl:apply-templates select="$start-element | $start-element/following-sibling::p"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果 HTML 文档最终出现在您输入的那个奇数命名空间中,您将必须在 XSLT 1 和 select 中将前缀绑定到该命名空间,并使用 prefix:local-name
例如xhtml:body
或 xhtml:p
其中名称空间声明为 xmlns:xhtml="../../../../external.html?link=http://www.w3.org/1999/xhtml"
.