Могу ли я оптимизировать это XSL-преобразование, которое берет записи с неизвестными столбцами и превращает их в формат сетки? - PullRequest
0 голосов
/ 28 января 2011

Я хотел бы оптимизировать XSL-преобразование ниже. Я включил пример входных данных и пример выходных данных создает. Входные данные взяты из базы данных с элементом Record для каждой строки и дочерними элементами для каждого выбранного столбца. Там может быть любое количество столбцов в любом порядке с любым именем. Я не знаю ничего об этом раньше времени (за исключением элемента Id ). Мне нужно преобразовать эти данные в формат сетки XML, который определяет используемые столбцы, а затем включает row элементы для каждой записи с cell элементами для каждого столбца. Входные данные включают элемент Columns , дочерние элементы которого определяют столбцы, которые должны отображаться в выходных данных. Я не знаю, какая из колонок может быть раньше времени. Все элементы в Столбцы должны появиться в выходных данных. Порядок столбцов / ячеек в выходных данных определяется атрибутом order в дочерних элементах Columns . Дочерние элементы Record , которые соответствуют именам дочерних элементов Columns , предоставляют данные для соответствующего элемента cell в выходных данных. Запись дочерних элементов, у которых нет соответствующих Columns дочерних элементов, игнорируются. Не все Столбцы дочерние элементы будут иметь соответствующие Запись дочерние элементы; для них нам нужно вывести пустой элемент cell .

Могу ли я заставить этот 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>

XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8"/>
    <xsl:key name="recordId" match="Record" use="generate-id(.)"/>
    <xsl:template match="/*">
        <grid name="exampleGrid">
            <xsl:for-each select="//Columns/*">
                <xsl:sort select="@order" order="ascending" data-type="number"/>
                <xsl:variable name="name" select="local-name(.)"/>
                <column label="{@label}" name="{$name}" align="{@align}"/>
            </xsl:for-each>
            <xsl:for-each select="Record">
                <xsl:call-template name="Record"/>
            </xsl:for-each>
        </grid>
    </xsl:template>
    <xsl:template name="Record">
        <xsl:variable name="recordId" select="generate-id(.)"/>
        <row key="{Id}">
            <xsl:for-each select="//Columns/*">
                <xsl:sort select="@order" order="ascending" data-type="number"/>
                <xsl:variable name="name" select="local-name(.)"/>
                <cell align="{@align}">
                    <xsl:value-of select="key('recordId', $recordId)/*[local-name(.) = $name]"/>
                </cell>
            </xsl:for-each>
        </row>
    </xsl:template>
</xsl:stylesheet>

Вывод 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>

1 Ответ

3 голосов
/ 28 января 2011

Вот как я бы выполнил эту задачу:

<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>

Вывод:

<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>

РЕДАКТИРОВАНИЕ : добавление решения XSLT 2.0, потому что это идеальный пример для инструкции xsl:perform-sort.

<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>

Примечание : узлы в $vColumns sequence сохраняет свою идентичность, и теперь мы можем использовать сопоставление с ними.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...