xslt 样式表--xml 到 csv:在动态结果文档 (exist-db) 上使用 for-each 循环时出错
xslt stylesheet--xml to csv: error when using for-each loop over dynamic results-document (exist-db)
xslt 新手又来了。作为序言,我会说——就像很多在这里提问的人一样——我来自不同的编程背景,所以我不完全理解 xslt 中的循环,我可能想出了一个扭曲的方法来尝试在这里做我想做的事,如果这一切都被严重误导,我 100% 愿意学习其他更好的方法。
我想做的事情: 遍历 xml 文件的集合并输出 csv 文件。我知道如何一个一个地执行此操作,但我想为一整批文件自动执行此操作。我试图找出在 xslt 中使用集合的方法,但在多次失败尝试后放弃了。
每个 tei/xml 文件都以唯一的三字符代码命名:esmpeople.xml、tdspeople.xml、ldbpeople.xml
我有另一个 tei/xml 文件列出了这些代码:codes.xml
所以我的想法是循环遍历codes.xml,抓取每个代码,然后寻找对应的xml文件,并输出一个csv文件。这是我的代码:
codes.xml
<?xml version="1.0"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml"
schematypens="http://purl.oclc.org/dsdl/schematron"?><?xml-stylesheet type="text/xsl" href="../xslt/csv-transform-people.xsl"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<teiHeader>
<fileDesc>
<titleStmt>
<title/>
</titleStmt>
<publicationStmt>
<p/>
</publicationStmt>
<sourceDesc>
<listBibl>
<bibl>
<note name="workref">OBRAESM</field>
<note name="workname">Escenas matritenses</field>
<note name="workauthor">Mesonero Romanos</field>
</bibl>
<bibl>
<note name="workref">OBRATDS</field>
<note name="workname">Tiempo de silencio</field>
<note name="workauthor">Luis Martín-Santos</field>
</bibl>
<bibl>
<note name="workref">OBRALDB</field>
<note name="workname">Luces de Bohemia</field>
<note name="workauthor">Ramón del Valle-Inclán</field>
</bibl>
</listBibl>
</sourceDesc>
</fileDesc>
<profileDesc><p/></profileDesc>
</teiHeader>
<text>
<body>
<p/>
</body>
</text>
</TEI>
esmpeople.xml
<listPerson>
<person xml:id="PERSSANISIDRO"/>
<person xml:id="PERSHORACIO"/>
<person xml:id="PERSBARTOLOMEARGENSOLA"/>
</listPerson>
tdspeople.xml
<listPerson>
<person xml:id="PERSPEDRO"/>
<person xml:id="PERSAMADOR"/>
<person xml:id="PERSRAMONYCAJAL"/>
<listPerson>
ldbpeople.xml
<listPerson>
<person xml:id="PERSMAXESTRELLA"/>
<person xml:id="PERSMADAMACOLLET"/>
<person xml:id="PERSBUEYAPIS"/>
<listPerson>
csv-转换-people.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csv="csv:csv" xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">
<xsl:output omit-xml-declaration="yes" method="text" encoding="utf-8"/>
<xsl:variable name="separator" select="','"/>
<xsl:variable name="newline" select="'
'"/>
<xsl:template match="/">
<xsl:for-each select="//tei:listBibl/tei:bibl">
<!--THIS WAS THE PROBLEM-->
<!--xsl:variable name="workref" select="//tei:note[@name='workref']"/-->
<!--FIX-->
<xsl:variable name="workref" select="tei:note[@name='workref']"/>
<xsl:variable name="workreflc" select="lower-case($workref)"/>
<xsl:variable name="workrefshort" select="replace($workref,'OBRA','')"/>
<xsl:variable name="workrefshortlc" select="lower-case($workrefshort)"/>
<xsl:variable name="sourcedocuri" select="concat('xmldb:exist://admin:password@00.00.00.00:8080/exist/xmlrpc/db/madrid/xml/',$workrefshortlc,'people.xml')"/>
<xsl:variable name="sourcedoc" select="doc($sourcedocuri)"/>
<xsl:variable name="sourcedocperson" select="$sourcedoc//tei:person"/>
<xsl:result-document href="xmldb:exist://admin:password@00.00.00.00:8080/exist/xmlrpc/db/madrid/csv/people2-{$workreflc}.csv">
<xsl:text>persref</xsl:text>
<xsl:value-of select="$separator"/>
<xsl:text>persworks</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:for-each select="$sourcedocperson">
<xsl:variable name="people">
<xsl:value-of select="@xml:id"/>
</xsl:variable>
<xsl:value-of select="$people"/>
<xsl:value-of select="$separator"/>
<xsl:value-of select="$workref"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
</xsl:result-document> </xsl:for-each>
</xsl:template>
</xsl:stylesheet>
预期结果:三个csv文件存入csv目录:people-obraesm.csv、people-obratds.csv、people-obraldb.csv
我得到的结果: people-obraesm.csv 100% 正确创建,但随后出现此错误:
发生错误:无法将多个结果文档写入同一 URI
所以我能够访问所有 xml 文件并将文件写入 /csv/ 目录,而不会出现权限问题。鉴于错误,我的样式表 and/or 通用逻辑中的循环似乎有问题。真的希望找出我哪里出了问题,因为每当我需要在 xslt 中使用循环时,我都会进入深度试错模式!
答案:
我根据 Martin 的建议更改了上面的 csv-transform-people.xsl,现在可以使用了!
在 <xsl:for-each select="//tei:listBibl/tei:bibl">
内部,上下文节点是经过处理的 //tei:listBibl/tei:bibl
,因此任何选择都应与其相关,也就是说,您需要 [=13] 而不是 <xsl:variable name="workref" select="//tei:note[@name='workref']"/>
=].
附带说明一下,如果使用 XSLT 2 或 3,通常最好在 XSLT 中使用合适的版本(即 version="2.0"
或 version="3.0"
),而不是 version="1.0"
,因为这会将 XSLT 处理器置于 XPath 1.0 向后兼容模式。只有将之前由 XSLT 1 处理器处理的 XSLT 1.0 样式表移动到 XSLT 2 或 3 处理器,您才会这样做。
xslt 新手又来了。作为序言,我会说——就像很多在这里提问的人一样——我来自不同的编程背景,所以我不完全理解 xslt 中的循环,我可能想出了一个扭曲的方法来尝试在这里做我想做的事,如果这一切都被严重误导,我 100% 愿意学习其他更好的方法。
我想做的事情: 遍历 xml 文件的集合并输出 csv 文件。我知道如何一个一个地执行此操作,但我想为一整批文件自动执行此操作。我试图找出在 xslt 中使用集合的方法,但在多次失败尝试后放弃了。
每个 tei/xml 文件都以唯一的三字符代码命名:esmpeople.xml、tdspeople.xml、ldbpeople.xml
我有另一个 tei/xml 文件列出了这些代码:codes.xml
所以我的想法是循环遍历codes.xml,抓取每个代码,然后寻找对应的xml文件,并输出一个csv文件。这是我的代码:
codes.xml
<?xml version="1.0"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml"
schematypens="http://purl.oclc.org/dsdl/schematron"?><?xml-stylesheet type="text/xsl" href="../xslt/csv-transform-people.xsl"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<teiHeader>
<fileDesc>
<titleStmt>
<title/>
</titleStmt>
<publicationStmt>
<p/>
</publicationStmt>
<sourceDesc>
<listBibl>
<bibl>
<note name="workref">OBRAESM</field>
<note name="workname">Escenas matritenses</field>
<note name="workauthor">Mesonero Romanos</field>
</bibl>
<bibl>
<note name="workref">OBRATDS</field>
<note name="workname">Tiempo de silencio</field>
<note name="workauthor">Luis Martín-Santos</field>
</bibl>
<bibl>
<note name="workref">OBRALDB</field>
<note name="workname">Luces de Bohemia</field>
<note name="workauthor">Ramón del Valle-Inclán</field>
</bibl>
</listBibl>
</sourceDesc>
</fileDesc>
<profileDesc><p/></profileDesc>
</teiHeader>
<text>
<body>
<p/>
</body>
</text>
</TEI>
esmpeople.xml
<listPerson>
<person xml:id="PERSSANISIDRO"/>
<person xml:id="PERSHORACIO"/>
<person xml:id="PERSBARTOLOMEARGENSOLA"/>
</listPerson>
tdspeople.xml
<listPerson>
<person xml:id="PERSPEDRO"/>
<person xml:id="PERSAMADOR"/>
<person xml:id="PERSRAMONYCAJAL"/>
<listPerson>
ldbpeople.xml
<listPerson>
<person xml:id="PERSMAXESTRELLA"/>
<person xml:id="PERSMADAMACOLLET"/>
<person xml:id="PERSBUEYAPIS"/>
<listPerson>
csv-转换-people.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csv="csv:csv" xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">
<xsl:output omit-xml-declaration="yes" method="text" encoding="utf-8"/>
<xsl:variable name="separator" select="','"/>
<xsl:variable name="newline" select="'
'"/>
<xsl:template match="/">
<xsl:for-each select="//tei:listBibl/tei:bibl">
<!--THIS WAS THE PROBLEM-->
<!--xsl:variable name="workref" select="//tei:note[@name='workref']"/-->
<!--FIX-->
<xsl:variable name="workref" select="tei:note[@name='workref']"/>
<xsl:variable name="workreflc" select="lower-case($workref)"/>
<xsl:variable name="workrefshort" select="replace($workref,'OBRA','')"/>
<xsl:variable name="workrefshortlc" select="lower-case($workrefshort)"/>
<xsl:variable name="sourcedocuri" select="concat('xmldb:exist://admin:password@00.00.00.00:8080/exist/xmlrpc/db/madrid/xml/',$workrefshortlc,'people.xml')"/>
<xsl:variable name="sourcedoc" select="doc($sourcedocuri)"/>
<xsl:variable name="sourcedocperson" select="$sourcedoc//tei:person"/>
<xsl:result-document href="xmldb:exist://admin:password@00.00.00.00:8080/exist/xmlrpc/db/madrid/csv/people2-{$workreflc}.csv">
<xsl:text>persref</xsl:text>
<xsl:value-of select="$separator"/>
<xsl:text>persworks</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:for-each select="$sourcedocperson">
<xsl:variable name="people">
<xsl:value-of select="@xml:id"/>
</xsl:variable>
<xsl:value-of select="$people"/>
<xsl:value-of select="$separator"/>
<xsl:value-of select="$workref"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>
</xsl:result-document> </xsl:for-each>
</xsl:template>
</xsl:stylesheet>
预期结果:三个csv文件存入csv目录:people-obraesm.csv、people-obratds.csv、people-obraldb.csv
我得到的结果: people-obraesm.csv 100% 正确创建,但随后出现此错误:
发生错误:无法将多个结果文档写入同一 URI
所以我能够访问所有 xml 文件并将文件写入 /csv/ 目录,而不会出现权限问题。鉴于错误,我的样式表 and/or 通用逻辑中的循环似乎有问题。真的希望找出我哪里出了问题,因为每当我需要在 xslt 中使用循环时,我都会进入深度试错模式!
答案: 我根据 Martin 的建议更改了上面的 csv-transform-people.xsl,现在可以使用了!
在 <xsl:for-each select="//tei:listBibl/tei:bibl">
内部,上下文节点是经过处理的 //tei:listBibl/tei:bibl
,因此任何选择都应与其相关,也就是说,您需要 [=13] 而不是 <xsl:variable name="workref" select="//tei:note[@name='workref']"/>
=].
附带说明一下,如果使用 XSLT 2 或 3,通常最好在 XSLT 中使用合适的版本(即 version="2.0"
或 version="3.0"
),而不是 version="1.0"
,因为这会将 XSLT 处理器置于 XPath 1.0 向后兼容模式。只有将之前由 XSLT 1 处理器处理的 XSLT 1.0 样式表移动到 XSLT 2 或 3 处理器,您才会这样做。