我们将XSL样式表应用于许多具有不同结构和标记的XML文件。我们希望对所有的文件使用单一的XSL样式表,如果添加了新的内容结构的XML文件,我们可以简单地添加新的xpath。
(我可以补充一点,这是用于Apache中的Solr的,输出文档需要以某种方式显示。)
到目前为止,我们已经成功地编写了复制各个字段的代码,如下所示:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt" xmlns:exslt="http://exslt.org/common" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" xalan:indent-amount="4" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:param name="fileName" />
<xsl:param name="fileURI" />
<xsl:param name="timeCreatedLong" />
<add>
<doc>
<!-- REQUIRED FIELDS. DO NOT CHANGE -->
<field name="fileName"><xsl:value-of select="$fileName" /></field>
<field name="fileURI"><xsl:value-of select="$fileURI" /></field>
<field name="timeCreatedLong"><xsl:value-of select="$timeCreatedLong" /></field>
<!-- //END OF REQUIRED FIELDS -->
<!-- DSV INTERNAL XML -->
<!-- Consignment Identifiers -->
<field name="consignmentIdentifiers"><xsl:value-of select="//consignmentlist/consignment/consignmentId" /></field>
<field name="consignmentIdentifiers"><xsl:value-of select="//consignmentlist/consignment/references/reference[@type = 'consignment_number']/value" /></field>
<!-- //Consignment Identifiers -->
<!-- Transport company information -->
<field name="carrier"><xsl:value-of select="//transport/transportservice/carriername" /></field>
<field name="carrierService"><xsl:value-of select="//transport/transportservice/carrierservicename" /></field>
<field name="transportMode"><xsl:value-of select="//transport/transportservice/transportmode" /></field>
<!-- //Transport company information -->
<!-- //DSV INTERNAL XML -->
<!-- POSTEN NORDIC LOGISTICS ORDER.XML -->
<!-- Consignment Identifiers -->
<field name="consignmentIdentifiers"><xsl:value-of select="//TransportJob/Consignment/@consignmentId" /></field>
<!-- //Consignment Identifiers -->
<!-- Transport company information -->
<field name="definedBy"><xsl:value-of select="//TransportJob/@definedBy" /></field>
<field name="carrier"><xsl:value-of select="//TransportJob/@profile" /></field>
<!-- //Transport company information -->
<!-- //POSTEN NORDIC LOGISTICS ORDER.XML -->
</doc>
</add>
</xsl:template>
</xsl:stylesheet>根据所处理的文件结构,输出如下所示:
<add>
<doc>
<field name="fileName">00373323993931432015_BOOKING.INTERNALXML</field>
<field name="fileURI">/usr/dropbox/Dropbox/shared/file-search/00373323993931432015_BOOKING.INTERNALXML</field>
<field name="timeCreatedLong">1377507872000</field>
<field name="consignmentIdentifiers"/>
<field name="consignmentIdentifiers">00373323993931432015</field>
<field name="carrier">DSV</field>
<field name="carrierService">DSV Mypack</field>
<field name="transportMode">ROAD</field>
<field name="consignmentIdentifiers"/>
<field name="definedBy"/>
<field name="carrier"/>
</doc>
</add>正如您所看到的,我们有一些空的/自关闭的元素,在将其发送到Solr服务器之前,我们希望删除这些元素。
因此,真正的问题是,在将这个XSL应用到它之后,是否有一种方法来删除生成的空标记?如前所述,我们希望在同一个XSL文件中完成此操作。
发布于 2013-08-27 13:11:18
一个改进的建议是有几个通用模板来匹配元素或属性,但是这些模板的参数可以设置为您希望输出的字段的“名称”。
第一个模板将实际输出字段元素,并相应地设置名称属性。
<xsl:template match="*|@*">
<xsl:param name="fieldName" />
<field name="{$fieldName}">
<xsl:value-of select="." />
</field>
</xsl:template>另一个将用于忽略没有值的这些元素或属性:
<xsl:template match="*[normalize-space()='']|@*[normalize-space()='']" />(请注意,更具体的模板(带有Xpath表达式检查空字符串的模板)将在这里获得优先级,而不是非特定的模板。
然后,不要写这个:
<field name="consignmentIdentifiers">
<xsl:value-of select="//consignmentlist/consignment/consignmentId" />
</field>你会写这个
<xsl:apply-templates select="//consignmentlist/consignment/consignmentId">
<xsl:with-param name="fieldName" select="'consignmentIdentifiers'" />
</xsl:apply-templates>与您希望输出的所有其他字段相似。因此,不必担心在每个语句周围编写xsl:if语句。这只是对你目前正在做的事情的一个小小的改变。
编辑:如果您真的想将XSLT应用于它自己的输出.
这样做的方法是使用“两通变换”。理想情况下,您可以在这里使用两个XSLT,但是如果您想要执行一个,那么一个是‘第一遍’,而不是简单地输出新元素,而是将现有代码包装在一个变量中。
<xsl:variable name="HereBeDragons">
<add>
<doc>
<field ...
</doc>
</add>
</xsl:variable>因此,您现在有了一个包含当前输出的变量,该变量包含空标记。现在,如果您正在使用XSLT2.0,您可以这样做,以便开始查找变量中元素的模板匹配
<xsl:apply-templates select="$HereBeDragons/*"/>但是在XSLT1.0中,您可能会得到一条消息,说明它不是节点集。在XSLT1.0中,变量实际上是存储“结果树片段”,需要转换为节点集,以允许使用模板。看起来您在这里使用EXSLT,所以在本例中,您应该能够做到这一点。
<xsl:apply-templates select="exslt:node-set($HereBeDragons)/*" />现在,在开始对变量应用模板之后,您只需添加模板就可以按需要处理数据。您将有一个标识实体模板的模板。
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>另一种,忽略你的空域
<xsl:template match="field[normalize-space()='']" />但是要小心,这些模板将同时适用于第一关和第二关。如果您想要一个模板来匹配第二遍中行为不同的特定元素,则可能需要使用模板上的模式属性来区分它们。
当然,以这种方式进行两次转换在内存或速度上都不是那么有效,这就是为什么首先建议将逻辑添加到原始XSLT中,而不是输出空标记。
发布于 2013-08-27 08:41:55
您可以在XSLT中添加检查,这些检查只在源不是空的情况下创建元素。例如,对于字段carrier,您可以这样做:
<xsl:if test="not(//transport/transportservice/carriername='')">
<field name="carrier">
<xsl:value-of select="//transport/transportservice/carriername" />
</field>
</xsl:if>如果这样做,就不会在输出中获得空字段。
编辑:如果您想检查输出,有一种非常有效的方法可以使用标识规则:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="field[normalize-space()='']"/>
</xsl:stylesheet>发布于 2013-08-27 09:29:21
假设XSLT2.0(您还没说过),我会这样做:
<xsl:sequence select="
f:field('carrier', //transport/transportservice/carriername),
f:field('carrierService', //transport/transportservice/carrierservicename),
f:field('transportMode', //transport/transportservice/transportmode),
..."/>将f:字段定义为
<xsl:function name="f:field" as="element(field)?">
<xsl:param name="name" as="xs:string"/>
<xsl:param name="value" as="xs:string?"/>
<xsl:if test="$value">
<field name="{$name}">
<xsl:value-of select="$value"/>
</field>
</xsl:if>
</xsl:function>https://stackoverflow.com/questions/18459538
复制相似问题