我是XSLT的新手,我正在尝试使用fmpxmlresult语法转换从Filemaker Pro生成的XML文件。 Filemaker以这种方式输出RAW XML:
<?xml version="1.0" encoding="UTF-8"?>
<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
<ERRORCODE>0</ERRORCODE>
<PRODUCT BUILD="02-13-2018" NAME="FileMaker" VERSION="ProAdvanced 16.0.5" />
<DATABASE DATEFORMAT="D/m/yyyy" LAYOUT="" NAME="fatture elettronica.fmp12" RECORDS="1" TIMEFORMAT="k:mm:ss " />
<METADATA>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="data" TYPE="DATE" />
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="ID" TYPE="TEXT" />
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="righe::descrizione" TYPE="TEXT" />
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="righe::prezzo" TYPE="TEXT" />
</METADATA>
<RESULTSET FOUND="1">
<ROW MODID="1" RECORDID="1">
<COL>
<DATA>31/08/2018</DATA>
</COL>
<COL>
<DATA>1</DATA>
</COL>
<COL>
<DATA>patate</DATA>
<DATA>pomodori</DATA>
<DATA>uva</DATA>
</COL>
<COL>
<DATA>100</DATA>
<DATA>50</DATA>
<DATA>70</DATA>
</COL>
</ROW>
</RESULTSET>
</FMPXMLRESULT>
在我的XSLT中,我选择了使用的字段
<xsl:value-of select="fmp:COL[1]/fmp:DATA"/>
它有效,但它有点混乱,因为我有一个包含大量字段的XML文件,并且很容易按编号对错误的字段进行处理。有没有办法使用元数据部分中列出的字段名称选择字段?我试图搜索,但我甚至无法想象要找到正确的关键字。谢谢
您可以定义一个键来保存字段名称,并使用count函数从中获取名称。
像这样的东西。
<!-- Define a key to get the first field and all fields that follow it by the field name -->
<xsl:key name="K" match="/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD" use="@NAME" />
<xsl:key name="K" match="/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD" use="following-sibling::fmp:FIELD/@NAME" />
<!-- Shortform to get a value for an attribute -->
<MyField SomeAttr="{fmp:COL[count(key('K', 'SomeAttr'))]}"/>
<!-- Format for getting a value for an element -->
<MyField>
<xsl:value-of select="fmp:COL[count(key('K', 'MyField'))]/fmp:DATA" />
</MyField>
此方法还具有以下优点:如果在FileMaker中更改字段导出顺序,则XSLT将保持同步。如果在FileMaker中更改字段名称,则只需更改XSLT中获取该字段的一个语句。
在纯XSLT / XPath 1中,很难找到一个紧凑的表达式,例如选择相应的FIELD
具有NAME
属性值ID
的列,你需要像<xsl:value-of select="fmp:COL[count($fields[@NAME = 'ID']/preceding-sibling::fmp:FIELD) + 1]/fmp:DATA"/>
这样的复杂选择:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
exclude-result-prefixes="fmp"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//fmp:ROW"/>
</xsl:template>
<xsl:variable name="fields" select="//fmp:FIELD"/>
<xsl:template match="fmp:ROW">
<xsl:value-of select="fmp:COL[count($fields[@NAME = 'ID']/preceding-sibling::fmp:FIELD) + 1]/fmp:DATA"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/94hvTzA/2
在XSLT 2或3中,您可以定义一个函数,该函数根据FIELD
属性值返回所需的NAME
的索引,并具有紧凑的<xsl:value-of select="COL[mf:col-pos('ID')]/DATA"/>
表达式:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://www.filemaker.com/fmpxmlresult"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:variable name="main-doc" select="/"/>
<xsl:key name="field" match="FIELD" use="@NAME"/>
<xsl:function name="mf:col-pos" as="xs:integer">
<xsl:param name="field-name" as="xs:string"/>
<xsl:sequence select="mf:col-pos($field-name, $main-doc)"/>
</xsl:function>
<xsl:function name="mf:col-pos" as="xs:integer">
<xsl:param name="field-name" as="xs:string"/>
<xsl:param name="field-anc" as="node()"/>
<xsl:for-each select="key('field', $field-name, $field-anc)">
<xsl:number/>
</xsl:for-each>
</xsl:function>
<xsl:template match="/">
<xsl:apply-templates select="//ROW"/>
</xsl:template>
<xsl:template match="ROW">
<xsl:value-of select="COL[mf:col-pos('ID')]/DATA"/>
</xsl:template>
</xsl:stylesheet>
我这样解决了:
<xsl:variable name="mdf" select="/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD" />
<xsl:variable name="ID" select="count($mdf[following-sibling::fmp:FIELD/@NAME = 'ID']) + 1" />
然后我调用变量:
<xsl:value-of select="fmp:COL[$ID]/fmp:DATA"/>