我是XSLT的新手。我需要汇总一些xml到pdf2txt.py中给出的PDF文件内容的信息。一些PDF很大(+ 100MB),甚至更大的是它们的xml输出。因此,通过几个xsltproc命令处理输出中的所有内容以便从不需要的内容中修剪xml代码似乎更有效(时间)。除此之外,还有一个带有文本内容的xml节点,我希望将其转换为其父节点的属性。
更具体地说,我有以下输入XML 文件结构:
<?xml version="1.0"?>
<pages>
<page id="1">
<text bbox="2831.881,1170.243,3124.184,1192.535">text11</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">sheet</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">P793</text>
</page>
<page id="2">
<text bbox="2831.881,1170.243,3124.184,1192.535">text21</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">sheet:</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">S234</text>
</page>
</pages>
我想将其转换为(请注意添加的网页属性):
<?xml version="1.0"?>
<pages>
<page id="1" sheet="P793">
<text bbox="2831.881,1170.243,3124.184,1192.535">text11</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">sheet</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">P793</text>
</page>
<page id="2" sheet="S234">
<text bbox="2831.881,1170.243,3124.184,1192.535">text21</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">sheet</text>
<text bbox="3149.641,1291.323,3318.336,1313.615">S234</text>
</page>
</pages>
按照XSLT: Add Attribute to parent based on child attribute value containing a specific string中的示例,我尝试使用以下 XSL样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="text"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="page">
<xsl:apply-templates select="@*"/>
<xsl:variable name="sheet" select="//text[contains(text(),'sheet')]/following::text[string-length()>3]"/>
<xsl:attribute name="sheet"><xsl:copy-of select="$sheet" /></xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是,我没有输出。我尝试用文本节点上的for-each循环替换变量技巧以定义新的页面属性,但后来我得到错误我试图在添加子节点后添加属性,我不太了解理解。
是否可以“预见”这样的节点值并使用它向父节点添加属性?怎么样?为什么我的样式表没有提供任何输出?
我的最终目标是同时删除与表单节点及其标签对应的XML文本行,但这看起来比这个前瞻,属性副本更容易解决,我稍后会处理它。
谢谢!
编辑:我简化了我的输入案例和xsl样式表。实际上,我在这里提供的示例有一个输出,但它是一个错误输出:
runtime error: file test.xsl line 18 element copy
Attribute nodes must be added before any child nodes to an element.
runtime error: file test.xsl line 13 element attribute
xsl:attribute: Cannot add attributes to an element if children have been already added to the element.
no result for -
这是一个错误,我还没弄清楚如何处理。谷歌搜索没有帮助。
答案 0 :(得分:2)
主要问题在于匹配page
的模板,您要做的第一件事就是创建一个属性
<xsl:template match="page">
<xsl:apply-templates select="@*"/>
但您实际上并未先复制page
元素,因此它会尝试将属性和子text
节点添加到之前创建的元素上;即pages
。对于匹配的第二个page
元素,它将尝试执行相同的操作,但是因为您无法向已添加子元素的元素添加属性而出现错误。
尝试使用此模板
<xsl:template match="page">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:variable name="sheet" select="text[contains(text(),'sheet')]/following-sibling::text[string-length()>3]"/>
<xsl:attribute name="sheet"><xsl:value-of select="$sheet" /></xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
请注意sheet
表达式的更改。以前,您使用//text
启动它,它将在文档中的任何位置找到第一个text
元素。需要删除//
,使其相对于当前page
节点。
此外,请注意使用following-sibling
而不是following
,以便将其自身限制为仅限当前page
元素下的兄弟节点。
最后,它是否只是您想要访问的后续兄弟姐妹?如果是这样,您可能需要在表达式
中添加额外条件<xsl:variable name="sheet" select="text[contains(text(),'sheet')]/following-sibling::text[1][string-length()>3]"/>
或许可以颠倒逻辑,然后用这种方式写
<xsl:variable name="sheet" select="text[string-length()>3][contains(preceding-sibling::text[1],'sheet')]"/>