我希望通过提及Filemaker,我不会失去任何人。我试图将它的XML导出转换为SSIS可用的东西。 FM的原生XML导出在同一XML文件的不同部分中具有字段名称和数据。这列出了我需要它做什么,我目前做了什么,以及底部的原始FM导出以供参考。我今天早上还没有看过XML翻译,所以请耐心等待:D。我可以根据需要发布更多信息。
<!-- What we actually want example -->
<?xml version="1.0" encoding="UTF-8"?>
<PRODUCTRECS>
<PRODUCT>
<name>Dr. Zim</name>
<address>1234 Internet Way</address>
<city/><state/><zip/>
</PRODUCT>
...
</PRODUCTRECS>
有没有办法让XSLt读取顶部的字段名称,并在翻译时将字段名称放在实际数据周围?目前,我只是选择IF语句这样的位置(这有效但非常依赖和混乱):
<!-- Current nightmare code, check for each individually and print it out -->
<xsl:template match="fmp:FMPXMLRESULT">
<PRODUCTRECS>
<xsl:for-each select="fmp:RESULTSET/fmp:ROW">
<PRODUCT>
<xsl:for-each select="fmp:COL">
<xsl:if test="position()=1">
<name><xsl:value-of select="fmp:DATA"/></name>
</xsl:if>
...
</xsl:for-each>
</PRODUCT>
</xsl:for-each>
</PRODUCTRECS>
</xsl:template>
这是Filemaker默认输出的内容:
<?xml version="1.0" encoding="UTF-8" ?>
<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
<ERRORCODE>0</ERRORCODE>
<PRODUCT BUILD="01-01-2009" NAME="FileMaker Pro" VERSION="10.0v3"/>
<DATABASE DATEFORMAT="M/d/yyyy" LAYOUT="" NAME="filename.fp7" RECORDS="10" TIMEFORMAT="h:mm:ss a"/>
<METADATA>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="name" TYPE="TEXT"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="address" TYPE="TEXT"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="city" TYPE="TEXT"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="state" TYPE="TEXT"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="zip" TYPE="TEXT"/>
</METADATA>
<RESULTSET FOUND="10">
<ROW MODID="0" RECORDID="1">
<COL><DATA>Dr. Zim</DATA></COL>
<COL><DATA>1234 Internet Way</DATA></COL>
<COL><DATA></DATA></COL>
<COL><DATA></DATA></COL>
<COL><DATA></DATA></COL>
...
</ROW>
...
</RESULTSET>
</FMPXMLRESULT>
期待着那里的大师XSLTers。 :)我的另一个问题是当原始文件在XML中存储为文本(00009.99000000)时,如何格式化数字价格为9.99美元的货币,但我可以处理这个。
答案 0 :(得分:6)
解决这个问题的一个优雅方法是:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
exclude-result-prefixes="fmp"
>
<!-- the key indexes the METADATA fields by their position -->
<xsl:key
name="kMetaData"
match="fmp:METADATA/fmp:FIELD"
use="count(preceding-sibling::fmp:FIELD) + 1"
/>
<!-- separate templates increase readability -->
<xsl:template match="/fmp:FMPXMLRESULT">
<PRODUCTRECS>
<xsl:apply-templates select="fmp:RESULTSET/fmp:ROW" />
</PRODUCTRECS>
</xsl:template>
<xsl:template match="fmp:ROW">
<PRODUCT>
<xsl:apply-templates select="fmp:COL" />
</PRODUCT>
</xsl:template>
<xsl:template match="fmp:COL">
<!-- column name lookup is high-speed because of the key -->
<xsl:element name="{string(key('kMetaData', position())/@NAME)}">
<xsl:value-of select="fmp:DATA" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
我系统上的哪些输出:
<PRODUCTRECS>
<PRODUCT>
<name>Dr. Zim</name>
<address>1234 Internet Way</address>
<city></city>
<state></state>
<zip></zip>
</PRODUCT>
</PRODUCTRECS>
但是,请注意,XML元素名称受制于比FileMaker列名更严格的规则。如果您的列名违反这些规则,上述内容将会崩溃并烧毁。
样式表的显着特征是:
<xsl:key>
用于快速查找节点 - 对于较大的输入,这应该会变得明显exclude-result-prefixes
以防止在结果中声明fmp
命名空间<xsl:element>
创建具有动态名称的元素preceding-sibling
XPath轴作为确定节点位置的方法(因为position()
函数在<xsl:key>
中不起作用继续询问是否有任何不清楚的地方。
您的其他问题(数字格式)在此处有一个答案:XSL: Formatting numbers, excluding trailing zeroes。
答案 1 :(得分:1)
您可以使用/
跳回到启动xpath查询的根目录
即/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/fmp:FMPXMLRESULT">
<PRODUCTRECS>
<xsl:apply-templates select="fmp:RESULTSET/fmp:ROW" />
</PRODUCTRECS>
</xsl:template>
<xsl:template match="fmp:RESULTSET/fmp:ROW">
<PRODUCT>
<xsl:apply-templates select="fmp:COL" />
</PRODUCT>
</xsl:template>
<xsl:template match="fmp:COL">
<xsl:variable name="currentPosition" select="position()" />
<xsl:element name="{/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD[position() = $currentPosition]/@NAME}">
<xsl:value-of select="fmp:DATA"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
这应该让你开始:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:fm="http://www.filemaker.com/fmpxmlresult">
<xsl:template match="/fm:FMPXMLRESULT">
<PRODUCTRECS>
<xsl:apply-templates select="fm:RESULTSET/fm:ROW"/>
</PRODUCTRECS>
</xsl:template>
<xsl:template match="fm:ROW">
<PRODUCT>
<!--
Use this if the element containing the NAME="FileMaker Pro" attribute is the one you want to use
for each row name.
<xsl:element name="{name(/fm:FMPXMLRESULT/*[@NAME='FileMaker Pro'])}">-->
<xsl:for-each select="fm:COL/fm:DATA">
<xsl:variable name="currentPos" select="position()"/>
<xsl:element name="{/fm:FMPXMLRESULT/fm:METADATA/fm:FIELD[position()=$currentPos]/@NAME}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
<!--</xsl:element>-->
</PRODUCT>
</xsl:template>
</xsl:stylesheet>
另外,请查看xsl:number的其他部分,或者只看number() function。