Xml 我可以优化这个XSL转换吗?它可以将包含未知列的记录转换为网格格式?

Xml 我可以优化这个XSL转换吗?它可以将包含未知列的记录转换为网格格式?,xml,optimization,xslt,Xml,Optimization,Xslt,我想优化下面的XSL转换。我已经包含了样本输入数据,样本输出是创建的。输入数据来自一个数据库,每行有一个记录元素,选定的每列有子元素。可以有任意数量、任意顺序和任意名称的列。我事先不知道这些(除了Id元素)。我需要将该数据转换为网格XML格式,定义所使用的列,然后为每个记录包含行元素,每个列包含单元格元素。输入数据包括一个Columns元素,其子元素定义了需要在输出中显示的列。我不知道哪一个专栏会提前发表。列下的所有元素都需要显示在输出中。输出中列/单元格的顺序由列子元素中的顺序属性确定。与列的

我想优化下面的XSL转换。我已经包含了样本输入数据,样本输出是创建的。输入数据来自一个数据库,每行有一个记录元素,选定的每列有子元素。可以有任意数量、任意顺序和任意名称的列。我事先不知道这些(除了Id元素)。我需要将该数据转换为网格XML格式,定义所使用的列,然后为每个记录包含元素,每个列包含单元格元素。输入数据包括一个Columns元素,其子元素定义了需要在输出中显示的列。我不知道哪一个专栏会提前发表。列下的所有元素都需要显示在输出中。输出中列/单元格的顺序由子元素中的顺序属性确定。与列的名称匹配的记录子元素为输出中相应的单元格元素提供数据Record忽略没有匹配列的子元素。并非所有子元素都将具有相应的记录子元素;对于它们,我们需要输出一个空的单元格元素

我可以让这个XSL工作得更好吗?我知道每个人都是“坏的”。我能再给这个做模板吗?谢谢

XML输入:

<?xml version="1.0" encoding="utf-8" ?>
<!-- The root element could have any name -->
<Data>
    <!-- There could be any number of Record elements -->
    <Record>
        <!-- Elements here may have any name and be in any order and may not be included in Columns -->
        <!-- For a particular XML file, all Record elements have the same child elements in the same order -->
        <Id>234542</Id>
        <Name>Tom Winter</Name>
        <SSN>XXX-XX-3317</SSN>
        <Facility>East Coast Hospital</Facility>
        <Status>AC</Status>
    </Record>
    <Record>
        <Id>345223</Id>
        <Name>John Doe</Name>
        <SSN>XXX-XX-2344</SSN>
        <Facility>St. Joseph West</Facility>
        <Status>DE</Status>
    </Record>
    <Columns>
        <!-- There may be any number of element here and they can be in any order -->
        <Name label="Patient Name" display="yes" order="2"/>
        <MRN label="MRN #" display="yes" order="1"/>
        <BirthDate label="Birth Date" align="right" display="yes" order="3"/>
        <SSN label="SSN" display="yes" order="9" notSortable="yes"/>
        <DischargeDate label="Discharge Date" align="right" display="no" order="7"/>
        <Address label="Address" display="yes" order="8"/>
        <Facility label="Facility" display="yes" order="4"/>
    </Columns>
</Data>

234542
汤姆·温特
XXX-XX-3317
东海岸医院
自动控制
345223
无名氏
XXX-XX-2344
圣约瑟夫西部酒店
判定元件
XSL:


XML输出:

<grid name="exampleGrid">
    <column label="MRN #" name="MRN" align="" />
    <column label="Patient Name" name="Name" align="" />
    <column label="Birth Date" name="BirthDate" align="right" />
    <column label="Facility" name="Facility" align="" />
    <column label="Discharge Date" name="DischargeDate" align="right" />
    <column label="Address" name="Address" align="" />
    <column label="SSN" name="SSN" align="" />
    <row key="234542">
        <cell align=""></cell>
        <cell align="">Tom Winter</cell>
        <cell align="right"></cell>
        <cell align="">East Coast Hospital</cell>
        <cell align="right"></cell>
        <cell align=""></cell>
        <cell align="">XXX-XX-3317</cell>
    </row>
    <row key="345223">
        <cell align=""></cell>
        <cell align="">John Doe</cell>
        <cell align="right"></cell>
        <cell align="">St. Joseph West</cell>
        <cell align="right"></cell>
        <cell align=""></cell>
        <cell align="">XXX-XX-2344</cell>
    </row>
</grid>

汤姆·温特
东海岸医院
XXX-XX-3317
无名氏
圣约瑟夫西部酒店
XXX-XX-2344

我将这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vColumns" select="/*/Columns/*"/>
    <xsl:template match="/*">
        <grid name="exampleGrid">
            <xsl:apply-templates select="$vColumns">
                <xsl:sort select="@order" data-type="number"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="Record"/>
        </grid>
    </xsl:template>
    <xsl:template match="Columns/*">
        <column label="{@label}" name="{local-name()}" align="{@align}"/>
    </xsl:template>
    <xsl:template match="Record">
        <xsl:variable name="vCurrent" select="."/>
        <row key="{Id}">
            <xsl:for-each select="$vColumns">
                <xsl:sort select="@order" data-type="number"/>
                <cell align="{@align}">
                    <xsl:value-of
                         select="$vCurrent/*[local-name()
                                              = local-name(current())]"/>
                </cell>
            </xsl:for-each>
        </row>
    </xsl:template>
</xsl:stylesheet>

注意:序列
$vColumns
中的节点保留了它们的标识,现在我们可以使用模式匹配来进行匹配。

我将这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vColumns" select="/*/Columns/*"/>
    <xsl:template match="/*">
        <grid name="exampleGrid">
            <xsl:apply-templates select="$vColumns">
                <xsl:sort select="@order" data-type="number"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="Record"/>
        </grid>
    </xsl:template>
    <xsl:template match="Columns/*">
        <column label="{@label}" name="{local-name()}" align="{@align}"/>
    </xsl:template>
    <xsl:template match="Record">
        <xsl:variable name="vCurrent" select="."/>
        <row key="{Id}">
            <xsl:for-each select="$vColumns">
                <xsl:sort select="@order" data-type="number"/>
                <cell align="{@align}">
                    <xsl:value-of
                         select="$vCurrent/*[local-name()
                                              = local-name(current())]"/>
                </cell>
            </xsl:for-each>
        </row>
    </xsl:template>
</xsl:stylesheet>

注意:序列
$vColumns
中的节点保留了它们的标识,现在我们可以使用模式匹配来匹配它们。

对于XSLT 1.0处理器,您可以使用扩展函数,如
exsl:node set
?在这种情况下,我建议只对
//Columns/*
进行一次排序,将结果存储在结果树片段中,用扩展函数将其转换为节点集,所有这些都在全局变量中完成,然后将变量与已排序的节点一起使用,而不是一次又一次地排序。@Martin Honnen:+1好建议。听起来不错。您知道这种类型的节点集函数在MSXML中是否可用吗?对于XSLT 1.0处理器,是否可以使用扩展函数,如
exsl:node set
?在这种情况下,我建议只对
//Columns/*
进行一次排序,将结果存储在结果树片段中,用扩展函数将其转换为节点集,所有这些都在全局变量中完成,然后将变量与已排序的节点一起使用,而不是一次又一次地排序。@Martin Honnen:+1好建议。听起来不错。您知道这种类型的节点集函数在MSXML中是否可用吗?非常好。不知道为什么我没有把实际的记录节点放在变量中而不是id中。现在看起来很明显@汤姆·温特:不客气@Flack:您可能还对我上一次更新中的XSLT2.0解决方案感兴趣。这是一个后续问题,因为我对XSL行话不太了解。在XSLT1.0示例中,您将$vRTFColumns和$vColumns的内容称为什么?我假设$vColumns包含一个节点集。可能已经回答了我自己的问题:是否有地方可以找到节点集和结果树片段之间差异的示例@汤姆·温特:是的,而且$VRTF列持有一张非常好的支票。不知道为什么我没有把实际的记录节点放在变量中而不是id中。现在看起来很明显@汤姆·温特:不客气@Flack:您可能还对我上一次更新中的XSLT2.0解决方案感兴趣。这是一个后续问题,因为我对XSL行话不太了解。在XSLT1.0示例中,您将$vRTFColumns和$vColumns的内容称为什么?我假设$vColumns包含一个节点集。可能已经回答了我自己的问题:是否有地方可以找到节点集和结果树片段之间差异的示例@汤姆·温特:是的,而且$VRTF列持有
<grid name="exampleGrid">
    <column label="MRN #" name="MRN" align="" />
    <column label="Patient Name" name="Name" align="" />
    <column label="Birth Date" name="BirthDate" align="right" />
    <column label="Facility" name="Facility" align="" />
    <column label="Discharge Date" name="DischargeDate" align="right" />
    <column label="Address" name="Address" align="" />
    <column label="SSN" name="SSN" align="" />
    <row key="234542">
        <cell align=""></cell>
        <cell align="">Tom Winter</cell>
        <cell align="right"></cell>
        <cell align="">East Coast Hospital</cell>
        <cell align="right"></cell>
        <cell align=""></cell>
        <cell align="">XXX-XX-3317</cell>
    </row>
    <row key="345223">
        <cell align=""></cell>
        <cell align="">John Doe</cell>
        <cell align="right"></cell>
        <cell align="">St. Joseph West</cell>
        <cell align="right"></cell>
        <cell align=""></cell>
        <cell align="">XXX-XX-2344</cell>
    </row>
</grid>
<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">
    <xsl:variable name="vRTFColumns">
        <xsl:for-each select="/*/Columns/*">
            <xsl:sort select="@order" data-type="number"/>
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="vColumns"
                  select="msxsl:node-set($vRTFColumns)/*"/>
    <xsl:template match="/*">
        <grid name="exampleGrid">
            <xsl:for-each select="$vColumns">
                <column label="{@label}" 
                        name="{local-name()}" 
                        align="{@align}"/>
            </xsl:for-each>
            <xsl:apply-templates select="Record"/>
        </grid>
    </xsl:template>
    <xsl:template match="Record">
        <xsl:variable name="vCurrent" select="."/>
        <row key="{Id}">
            <xsl:for-each select="$vColumns">
                <cell align="{@align}">
                    <xsl:value-of
                         select="$vCurrent/*[local-name()
                                              = local-name(current())]"/>
                </cell>
            </xsl:for-each>
        </row>
    </xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vColumns" as="element()*">
        <xsl:perform-sort select="/*/Columns/*">
            <xsl:sort select="@order" data-type="number"/>
        </xsl:perform-sort>
    </xsl:variable>
    <xsl:template match="/*">
        <grid name="exampleGrid">
            <xsl:apply-templates select="$vColumns"/>
            <xsl:apply-templates select="Record"/>
        </grid>
    </xsl:template>
    <xsl:template match="Columns/*">
        <column label="{@label}" name="{local-name()}" align="{@align}"/>
    </xsl:template>
    <xsl:template match="Record">
        <xsl:variable name="vCurrent" select="."/>
        <row key="{Id}">
            <xsl:for-each select="$vColumns">
                <cell align="{@align}">
                    <xsl:value-of
                         select="$vCurrent/*[local-name()
                                             = local-name(current())]"/>
                </cell>
            </xsl:for-each>
        </row>
    </xsl:template>
</xsl:stylesheet>