XSLT - 如何正确解析 XHTML 文本

XSLT - How to I correctly parse XHTML text

我正在尝试将一些 HTML(当然是 XHTML!)文档解析为 XML,以便我以后可以将它们处理成其他文档格式。我已经能够递归解析节点树以提取节点和属性信息,但它不能很好地处理实际文本。

这是我的示例来源:

<div>
    <p>
        <a href='http://google.com'>Text in A</a>
    </p>
    <p>Text in P</p>
    <p>How to <strong>emphasise</strong> text</p>
</div>

我希望它产生这样的东西:

<div-tag>
    <id>first</id>
    <p-tag>
        <a-tag>
            <text>Text in A</text>
            <link>http://google.com</link>
        </a-tag>
    <p-tag>
    <p-tag>
        <text>Text in P</text>
    </p-tag>
    <p-tag>
        <text>How to</text>
    </p-tag>
    <strong-tag>
        <text>emphasise</text>
    </strong-tag>
    <p-tag>
        <text>text</text>
    </p-tag>
</div-tag>

我正在使用应用模板递归遍历树:

<xsl:template match="*">
<xsl:variable name="node-name" select="concat(local-name(),'-tag')"/>
<xsl:element name="{$node-name}">
    <xsl:choose>
        <xsl:when test="count(child::*) = 0">
            <xsl:if test="text()">
                <xsl:element name="text"><xsl:value-of select="text()"/></xsl:element>
                <xsl:if test="@href">
                    <xsl:element name="link"><xsl:value-of select="@href"/></xsl:element>
                </xsl:if>
            </xsl:if>
        </xsl:when>
        <xsl:otherwise>
            <xsl:apply-templates select="child::*"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:element>

它最终丢失了一些文本,其中一个节点有文本和子节点,尤其是嵌套的子节点(在我的示例中)。如果我将它设置为在它找到任何文本时输出文本(而不仅仅是在没有子节点时),它最终也会显示子节点的文本。

通读这里的问题和答案,我找到了正确解析文本的方法...

<xsl:template match="div//text()">
    <xsl:variable name="node-name" select="concat(local-name(..),'-tag')"/>
    <xsl:element name="{$node-name}">
        <text">
            <xsl:value-of select="normalize-space()" />
        </text>
    </xsl:element>
</xsl:template>

...当然,它不会选择没有文本的节点。它错过了第一个 p 节点,因为它本身没有任何文本。 (我意识到在拆分段落时我需要小心处理段落,如上所述,但那是明天的问题!

我确信一定有一种方法可以将 HTML 解析为更简单的 XML 结构,但我现在很困惑。有什么建议吗?

仅根据一个小示例和没有实现的代码,很难说出您到底想要实现什么。以下对您有用吗?

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*">
    <xsl:element name="{local-name()}-tag">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="@href">
    <link>
        <xsl:value-of select="."/>
    </link>
</xsl:template>

<xsl:template match="text()">
    <text>
        <xsl:copy-of select="."/>
    </text>
</xsl:template>

</xsl:stylesheet>