XSL getting value of immediately preceding element/@attribute

我的未来我决定 提交于 2019-12-11 11:49:06

问题


I have an XML text file, divided into <deposition>s, each marked up with <footnote> and <appnote>containing identifying numbers and letters for footnote purposes. Now I want to cycle through those (XSL 3.0/Saxon) and then get an attribute of the element immediately preceding it to populate a new footnote 'block' called <footnotes> at the end of each <deposition> . Test can be found here http://xsltfiddle.liberty-development.net/948Fn5a/16

XML:

<?xml version="1.0" encoding="UTF-8"?>
<corpus>
<deposition>
    <deposition-title>Praesent vitae</deposition-title>
    <text>
        <seg n="seg1" type="not_foo">Lorem ipsum dolor sit amet, consectetur 
            adipiscing elit. Vivamus<note2 n="abc">another note 2</note2><appnote>a</appnote> ultrices consequat facilisis. 
            Suspendisse a odio<note n="def">foo note</note><footnote>1</footnote> in lobortis. Aenean 
            non dui scelerisque, rutrum est at, cursus sem.</seg>
        <seg n="seg2" type="foo">Ut pharetra bibendum ipsum, portitor 
            velit pharetra quis. Aeneano<note n="ghi">foo note</note><footnote>2</footnote> purus. Praesent 
            aliquam viverra tellus<note n="jkl">another note</note><footnote>3</footnote> in condimentum.</seg><footnote>4</footnote>
    </text>
</deposition>
<deposition>
    <deposition-title>Elementum arcu non</deposition-title>
    <text>
        <seg n="seg1" type="foo">Curabitur pulvinar leo eget. Orci varius 
            natoque penatibus et magnis dis<note n="mno">foo note</note><footnote>1</footnote> montes, 
            nascetur ridiculus mus.</seg><footnote>2</footnote>
        <seg n="seg2" type="foo">Curabitur pulvinar leo eget. Orci varius 
            natoque penatibus<note2  n="pqr">another note 2</note2><appnote>a</appnote> et 
            magnis dis<note n="stu">foo note</note><footnote>3</footnote> montes, 
            nascetur ridiculus mus.</seg><footnote>4</footnote>
        <seg n="seg3" type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
            Nulla rutrum vel diam vel posuere. Aliquam pellentesque 
            malesuada elit sed tempor.</seg>
    </text>
</deposition>
<deposition>
    <deposition-title>Elementum arcu non</deposition-title>
    <text>
        <seg n="seg1" type="foo">Curabitur pulvinar leo eget. Orci varius 
            natoque penatibus et magnis dis<note n="vwx">foo note</note><footnote>1</footnote> montes, 
            nascetur ridiculus mus.</seg><footnote>2</footnote>
        <seg n="seg2" type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
            Nulla rutrum vel diam vel posuere. Aliquam<note2  n="yz">another note 2</note2><appnote>a</appnote> pellentesque 
            malesuada elit sed tempor.</seg>
    </text>
</deposition>
</corpus>

XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="xs"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="deposition">
  <deposition>
    <xsl:apply-templates/> 
    <footnotes>
        <xsl:for-each select="text//footnote">
            <xsl:variable name="pos" select="./current() - 1"/>
            <footitem>
                <xsl:value-of select=". || '='"/><xsl:value-of select="preceding::node()[$pos]/@n"/>
            </footitem>
        </xsl:for-each>
        <xsl:for-each select="text//appnote">
            <xsl:variable name="pos" select="./current() - 1"/>
            <appitem>
                <xsl:value-of select=". || '='"/><xsl:value-of select="preceding::node()[$pos]/@n"/>
            </appitem>
        </xsl:for-each>
    </footnotes>
  </deposition>
</xsl:template>

</xsl:stylesheet>

However the result is unexpected, likely due to misunderstanding current() and preceding::node.

For example, for the first <deposition> I would expect the following to appear after the last seg in each deposition:

<footnotes>
  <footitem>1=def</footitem>
  <footitem>2=ghi</footitem>
  <footitem>3=jkl</footitem>
  <footitem>4=seg1</footitem>
</footnotes>
<appnotes>
  <appitem>a=abc</appitem>
</appnotes>

But I am getting Error executing XSLT ....cannot convert string "a" to double.

(NB: this example is generic and the previous element could be one of many names, so hardcoding the name of an element is not a feasible solution.)

Many, many thanks in advance for all the help with this massive project!


回答1:


I think you simply want

        <xsl:for-each select="text//footnote">
            <footitem>
                <xsl:value-of select=". || '='"/><xsl:value-of select="preceding-sibling::*[1]/@n"/>
            </footitem>
        </xsl:for-each>
         <xsl:for-each select="text//appnote">
            <appitem>
                <xsl:value-of select=". || '='"/><xsl:value-of select="preceding-sibling::*[1]/@n"/>
            </appitem>
        </xsl:for-each>

although that gives (http://xsltfiddle.liberty-development.net/948Fn5a/17)

<footnotes><footitem>1=def</footitem><footitem>2=ghi</footitem><footitem>3=jkl</footitem><footitem>4=seg2</footitem><appitem>a=abc</appitem></footnotes></deposition>

so 4=seg2 and not 4=seg1.

And you don't really need two adjacent value-ofs, you can use e.g.

<xsl:value-of select="., preceding-sibling::*[1]/@n" separator="="/>

http://xsltfiddle.liberty-development.net/948Fn5a/18 or

                <xsl:value-of select=". || '=' || preceding-sibling::*[1]/@n"/>

http://xsltfiddle.liberty-development.net/948Fn5a/19



来源:https://stackoverflow.com/questions/48132710/xsl-getting-value-of-immediately-preceding-element-attribute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!