【问题标题】:XSLT: How do I match every descendant individually?XSLT:如何单独匹配每个后代?
【发布时间】:2017-08-13 20:43:21
【问题描述】:

我正在尝试展平以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://pretend.namespace">
    <record>
        <first>1</first>
        <second>2</second>
        <tricky>
            <taxing>3</taxing>
            <mayhem>
                <ohno>4</ohno>
                <boom>5</boom>
            </mayhem>
        </tricky>
    </record>
    <record>
        <first>1</first>
        <second>2</second>
        <tricky>
            <taxing>3</taxing>
            <mayhem>
                <ohno>4</ohno>
                <boom>5</boom>
            </mayhem>
        </tricky>
    </record>
    <record>
        <first>1</first>
        <second>2</second>
        <tricky>
            <taxing>3</taxing>
            <mayhem>
                <ohno>4</ohno>
                <boom>5</boom>
            </mayhem>
        </tricky>
    </record>
</root>

每记录一行,丢弃记录中的复杂结构。

1,2,3,4,5
1,2,3,4,5
1,2,3,4,5

使用这个 XSLT

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:p="http://pretend.namespace">

<xsl:strip-space elements="*"/> <!-- remove unwanted whitespace? -->

 <!-- Match every p:record -->
<xsl:template match="p:record">
    <xsl:apply-templates/> <!-- now we're inside a <record> do what you can with the contents then give a line return -->
    <xsl:text>&#xA;</xsl:text><!-- this is a line return -->
</xsl:template>

<xsl:template match="p:record//*">
    <xsl:value-of select="."></xsl:value-of><xsl:text>,</xsl:text>
</xsl:template>

<xsl:template match="text()"/> <!-- WORKS: prevents "default output" to aid debugging -->

</xsl:stylesheet>

但是尽管尝试了几个小时,我还是无法让它访问每个后代并用逗号分隔它们,我得到了这个:

1,2,345,
1,2,345,
1,2,345,

我需要做些什么才能让它单独对待所有孙子及以下? (每行最后的逗号不是问题)

谢谢!

编辑:这个问题之后的讨论表明,Herong Yang 博士的 Notepad++ XML 工具似乎只支持 XSLT 1.0

【问题讨论】:

    标签: xslt descendant


    【解决方案1】:

    为什么不简单

    <xsl:strip-space elements="*"/>
    <xsl:template match="record">
      <xsl:value-of select="descendant::text()/data()" separator=","/>
      <xsl:text>&#xa;</xsl:text>
    </xsl:template>
    

    (需要使用data() 进行显式原子化,否则相邻的文本节点会在没有分隔符的情况下连接起来)。

    【讨论】:

    • 谢谢。 Notepad++ 的 XML 工具声明“无法应用,请确保 XSL 有效”,除非我删除 /data() (这使这一点失效)。记事本++可能不是一个完整的实现吗?
    • @Mike,data() 是 XPath/XSLT 2.0 中引入的一个函数,就像 separator 属性一样,所以如果您遇到错误,那么您的编辑器可能只支持 XSLT 1.0 或至少默认配置仅支持 XSLT 1.0。
    • @Mike,XSLT 2.0 已经存在了 10 年以上,如果您被限制使用旧版本,则需要说明。
    • 多谢了 - 杨博士的 Notepad++ XML 工具插件似乎只支持 XSLT 1.0。我不知道 - 没有明确记录是否是这种情况。希望本次讨论能帮助其他人识别此限制!
    • 标记为正确但免责声明:我还没有在 XSLT 2.0 处理器中尝试过这个
    【解决方案2】:

    怎么样:

    XSLT 1.0

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:p="http://pretend.namespace">
    <xsl:output method="text" encoding="utf-8" />
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="p:record">
        <xsl:apply-templates/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
    
    <xsl:template match="*[not(*)]">
        <xsl:value-of select="."/>
        <xsl:if test="position()!=last()">
            <xsl:text>,</xsl:text>
        </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 谢谢回复,我不懂XPath表达式*[not(*)]是什么意思?我把它读作“除了一切之外的一切”!编辑:如果我不得不猜测,也许它的意思是“所有孩子不包括(孩子的)所有孩子”,从而使比赛不那么贪婪?
    • 表示没有子元素的元素——实际上是*[not(child::*)]的缩写。这里假设每个叶子节点都是一个数据单元。
    • 再次感谢您。这已根据需要用逗号分隔叶子,但尝试在每条记录的最后一个子项之后插入换行符不再有效。对于未来的参考:(由于我未能在示例中反映的结构,我删除了您的“如果最后”测试:在真实数据中,记录中有多个“最深”结构,这在每个之后都省略了逗号他们)
    • 您可以在这里看到它的工作原理:xsltransform.net/93dEHGm 如果您输入的内容不同,请编辑您的问题并澄清 - 或发布一个新问题。
    • 谢谢 - 如果我发现差异我会更新这个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-25
    • 2019-11-13
    • 2016-10-20
    • 1970-01-01
    相关资源
    最近更新 更多