xpath - 在给定兄弟之前、之后和之间转换混合文本和节点

标签 xpath xslt-1.0

我正在寻找修复一些在段落标记中具有 block 级元素的 XML。 XML 类似于:

<p>
   This is some text with <tag>some other markup</tag> in it that also needs transformation
   <div>
     Oh no here is a block element
   </div>
   It is even worse as <i>there is more content</i> between that needs transform
   <div>
     more block content
   </div>
   more text
</p>

因此该模式是任意文本和节点与 block 级元素的混合。此处可以是任意数量的这些 div 和其他文本,因此使用索引的答案并不适用于所有情况。

我希望将其转换为

 <p>This is some text with <transformed-tag>some other markup</transformed-tag> in it that also needs transformation</p>
 <div>Oh no here is a block element</div>
 <p>It is even worse as <i>there is more content</i> between that needs transform</p>
 <div>more block content</div>
 <p>more text</p>

所以本质上我想捕获不在 div 标签中的 p 的所有后代,并用 p 标签包装每个,同时保留文本和 div 的顺序。我已经尝试了一切,但不确定如何捕获 div 之间的文本。我已经能够使用将数据从第一个 blob 转换到第一个 div,然后将数据从最后一个 div 转换到末尾

<xsl:template match="p[following::div]">
   <p><xsl:apply-templates/></p>
</xsl:template>


<xsl:template match="p[preceding::div]">
   <p><xsl:apply-templates/></p>
</xsl:template>

更新:使输出匹配。在 div 和 p 标签中输出的文本也需要应用模板,因为其中可能嵌套有需要应用样式的元素。

最佳答案

好吧,那么我在这里错过了什么?

<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:template match="/p">
    <root>
        <xsl:apply-templates select="node()[1]" mode="first"/>
        <xsl:apply-templates select="div[1]"/>
    </root>
</xsl:template>

<xsl:template match="node()" mode="first">
    <p>
        <xsl:copy/>
        <xsl:apply-templates select="following-sibling::node()[1][not(self::div)]" mode="next"/>
    </p>
</xsl:template>

<xsl:template match="node()" mode="next">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
    <xsl:apply-templates select="following-sibling::node()[1][not(self::div)]" mode="next"/>
</xsl:template>

<xsl:template match="tag" mode="next">
    <transformed-tag>
        <xsl:apply-templates/>
    </transformed-tag>
    <xsl:apply-templates select="following-sibling::node()[1][not(self::div)]" />
</xsl:template>

<xsl:template match="div">
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="following-sibling::node()[1][not(self::div)]" mode="first"/>
    <xsl:apply-templates select="following::div[1]"/>
</xsl:template>

</xsl:stylesheet>

关于xpath - 在给定兄弟之前、之后和之间转换混合文本和节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23553147/

相关文章:

xml - XSLT 1.0 将定界字符串转换为节点集

xml - XSLT 中的秒数

XSLT:检查列表中是否存在值

html - 如何为这个 HTML 编写 XPath 和 CSS?

.net - 使用linq2xml订购xml文件

php - SimpleXML xpath 到具有特定属性值的元素?

xslt - 如何使用 xslt 将 json 转换为 xml

xml - 对 xsl 中的备用表行应用备用类名 :foreach loop

xml - 如何使用 XSLT 获取 XML 属性的首字母?

c# - 属性值中的 XPath 通配符