Xml 嵌套属性的XSL转换

Xml 嵌套属性的XSL转换,xml,xslt,filemaker,Xml,Xslt,Filemaker,我手头的任务是将以下(简化的)示例XML中的文本和任何相关字体属性剥离到FileMaker数据库中。XML示例: <Font Id="Arial" Script="normal" Size="32" Underlined="no" Italic="no" Weight="normal"> <Paragraph> <Text>This <Font Italic="yes">word</Font> is italic

我手头的任务是将以下(简化的)示例XML中的文本和任何相关字体属性剥离到FileMaker数据库中。XML示例:

<Font Id="Arial" Script="normal" Size="32" Underlined="no" Italic="no" Weight="normal">
    <Paragraph>
        <Text>This <Font Italic="yes">word</Font> is italic</Text>
        <Text>This entire line has no formatting</Text>
        <Text>This<Font Italic="yes">line</Font><Font Underlined="yes" Italic = "yes"> has multiple formats</Font></Text>
    </Paragraph>

    <Paragraph>
        <Text>This is the first line of the second paragraph and has no formatting</Text>
        <Text>This line also has no formatting</Text>
        <Text><Font Underlined="yes">This entire line is underlined</Font></Text>
    </Paragraph>
</Font>

当然,我无法预测何时何地应用格式。我希望我已经讲清楚了,并且提前非常感谢您为我完成这项任务提供的任何建议。

我建议您尝试这样的方法,至少作为您的出发点:

XSLT

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Font">
    <FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
        <METADATA>
            <FIELD NAME="Text"/>
            <FIELD NAME="IsItalic" TYPE="NUMBER"/>
            <FIELD NAME="IsUnderline" TYPE="TEXT"/>
            <FIELD NAME="Paragraph" TYPE="TEXT"/>
        </METADATA>
        <RESULTSET>
            <!-- create a record for each text node, descendant of Paragraph -->
            <xsl:for-each select="Paragraph//text()">
                <ROW>
                    <!-- get the value of the current text node itself  -->
                    <COL><DATA><xsl:value-of select="."/></DATA></COL>
                    <!-- get the value of @Italic from the nearest ancestor that has such attribute -->
                    <COL><DATA><xsl:value-of select="ancestor::*[@Italic][1]/@Italic"/></DATA></COL>
                    <!-- get the value of @Underlined from the nearest ancestor that has such attribute -->
                    <COL><DATA><xsl:value-of select="ancestor::*[@Underlined][1]/@Underlined"/></DATA></COL>
                    <!-- get the ID of the ancestor Paragraph -->
                    <COL><DATA><xsl:value-of select="generate-id(ancestor::Paragraph)"/></DATA></COL>
                </ROW>
            </xsl:for-each>
        </RESULTSET>
    </FMPXMLRESULT>
</xsl:template>

</xsl:stylesheet>
结果如下所示(列表视图中显示两条记录):


您可能需要添加您期望的实际输出格式。XSLT是一种XML转换语言。换句话说,它可以将XML转换为不同的格式。它无法为您的数据库或类似的内容提供数据。指定数据库可以实际读取的文件格式,上面的示例可能会概述您的意图,但这不是您能够实际使用的任何格式。结果显示的格式非常有问题,并且只有在每个
段落
(记录)具有完全相同数量的文本段(字段)时才能使用-这似乎不太可能。如果要“捕获每个数据片段及其属性”,则应为每个片段创建单独的记录。@Tomalak问题标记为
filemaker
。这指定了目标XML模式。@michael我认为filemaker XML模式不是公共知识(我们也不需要查找它)。谢谢您的回答。XSLT实际上可以很好地作为Filemaker和XML文档之间的桥梁。也许我没有提供足够的信息。下面是当前XSLT代码,它适用于没有嵌套字体属性的整行文本,或完全由字体属性包围的文本行:非常感谢!这看起来会很完美。问题是,我不太明白发生了什么。由于我不是XSLT专家(还不是!),我想知道您是否可以向我介绍一个资源,其中解释了诸如在段落//文本中使用双正斜杠、select=“”中的句点以及指示代码查找的内容*[下划线][1]。@JonathanA我已经在代码中添加了一些注释。至于资源,有教程、书籍,最后还有标准本身。是的……在这里发布之前,已经在网络和论坛上搜索了好几个小时。还没有找到任何能充分解释它的东西。再次感谢你花时间来帮助我……你让我走上了正确的道路!奇怪的是,如何修改上述代码,将每个段落分割成一个单独的FileMaker记录(显然有多个字段),而不是将每个文本片段分割成单独的记录。@JonathanA正如我在对您的问题的评论中所说,您可能会遇到问题,因为所需字段的数量事先未知。导入时不能像创建记录一样创建字段。此外,拥有这样的数据库结构将是非常糟糕的。试想一下:为了找到所有斜体文本,您必须搜索n个字段而不是一个字段,并且您无法单独显示它们。
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Font">
    <FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
        <METADATA>
            <FIELD NAME="Text"/>
            <FIELD NAME="IsItalic" TYPE="NUMBER"/>
            <FIELD NAME="IsUnderline" TYPE="TEXT"/>
            <FIELD NAME="Paragraph" TYPE="TEXT"/>
        </METADATA>
        <RESULTSET>
            <!-- create a record for each text node, descendant of Paragraph -->
            <xsl:for-each select="Paragraph//text()">
                <ROW>
                    <!-- get the value of the current text node itself  -->
                    <COL><DATA><xsl:value-of select="."/></DATA></COL>
                    <!-- get the value of @Italic from the nearest ancestor that has such attribute -->
                    <COL><DATA><xsl:value-of select="ancestor::*[@Italic][1]/@Italic"/></DATA></COL>
                    <!-- get the value of @Underlined from the nearest ancestor that has such attribute -->
                    <COL><DATA><xsl:value-of select="ancestor::*[@Underlined][1]/@Underlined"/></DATA></COL>
                    <!-- get the ID of the ancestor Paragraph -->
                    <COL><DATA><xsl:value-of select="generate-id(ancestor::Paragraph)"/></DATA></COL>
                </ROW>
            </xsl:for-each>
        </RESULTSET>
    </FMPXMLRESULT>
</xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.filemaker.com/fmpxmlresult">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Font">
    <FMPXMLRESULT>
        <METADATA>
            <FIELD NAME="Line 1a Text"/>
            <FIELD NAME="Line 1a Italic"/>
            <FIELD NAME="Line 1a Underlined"/>

            <FIELD NAME="Line 1b Text"/>
            <FIELD NAME="Line 1b Italic"/>
            <FIELD NAME="Line 1b Underlined"/>

            <FIELD NAME="Line 1c Text"/>
            <FIELD NAME="Line 1c Italic"/>
            <FIELD NAME="Line 1c Underlined"/>

            <FIELD NAME="Line 2a Text"/>
            <FIELD NAME="Line 2a Italic"/>
            <FIELD NAME="Line 2a Underlined"/>
            <FIELD NAME="Line 2b Text"/>
            <FIELD NAME="Line 2b Italic"/>
            <FIELD NAME="Line 2b Underlined"/>

            <FIELD NAME="Line 2c Text"/>
            <FIELD NAME="Line 2c Italic"/>
            <FIELD NAME="Line 2c Underlined"/>

            <FIELD NAME="Line 3a Text"/>
            <FIELD NAME="Line 3a Italic"/>
            <FIELD NAME="Line 3a Underlined"/>

            <FIELD NAME="Line 3b Text"/>
            <FIELD NAME="Line 3b Italic"/>
            <FIELD NAME="Line 3b Underlined"/>

            <FIELD NAME="Line 3c Text"/>
            <FIELD NAME="Line 3c Italic"/>
            <FIELD NAME="Line 3c Underlined"/>
        </METADATA>
        <RESULTSET>
            <!-- create a record for each Paragraph -->
            <xsl:for-each select="Paragraph">
                <ROW>
                    <!-- for each line ...  -->
                    <xsl:for-each select="Text">
                        <xsl:variable name="text-nodes" select=".//text()" />
                        <!-- process the first three text nodes  -->
                        <xsl:call-template name="create-cells">
                            <xsl:with-param name="text-node" select="$text-nodes[1]"/>
                        </xsl:call-template>
                        <xsl:call-template name="create-cells">
                            <xsl:with-param name="text-node" select="$text-nodes[2]"/>
                        </xsl:call-template>
                        <xsl:call-template name="create-cells">
                            <xsl:with-param name="text-node" select="$text-nodes[3]"/>
                        </xsl:call-template>
                    </xsl:for-each> 
                </ROW>
            </xsl:for-each>
        </RESULTSET>
    </FMPXMLRESULT>
</xsl:template>

<xsl:template name="create-cells">
    <xsl:param name="text-node"/>
    <!-- get the value of the text node itself  -->
    <COL><DATA><xsl:value-of select="$text-node"/></DATA></COL>
    <!-- get the value of @Italic from the nearest ancestor that has such attribute -->
    <COL><DATA><xsl:value-of select="$text-node/ancestor::*[@Italic][1]/@Italic"/></DATA></COL>
    <!-- get the value of @Underlined from the nearest ancestor that has such attribute -->
    <COL><DATA><xsl:value-of select="$text-node/ancestor::*[@Underlined][1]/@Underlined"/></DATA></COL>
</xsl:template>

</xsl:stylesheet>