XSLT: Как исключить пустые элементы из моего результата?

У меня есть довольно сложный лист xslt, преобразовывающий один xml формат к другому использованию шаблоны. Однако в получающемся xml, у меня должны быть все пустые исключенные элементы. Как это сделано?

Это - то, как основа xslt похожа:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:far="http://www.itella.com/fargo/fargogate/" xmlns:a="http://tempuri.org/XMLSchema.xsd" xmlns:p="http://tempuri.org/XMLSchema.xsd">
    <xsl:import href="TransportCDMtoFDM_V0.6.xsl"/>
    <xsl:import href="ConsignmentCDMtoFDM_V0.6.xsl"/>
    <xsl:template match="/">
        <InboundFargoMessage>
            <EdiSender>
                <xsl:value-of select="TransportInformationMessage/SenderId"/>
            </EdiSender>
            <EdiReceiver>
                <xsl:value-of select="TransportInformationMessage/RecipientId"/>
            </EdiReceiver>
            <EdiSource>
                <xsl:value-of select="TransportInformationMessage/Waybill/Parties/Consignor/Id"/>
            </EdiSource>
            <EdiDestination>FARGO</EdiDestination>
            <Transportations>
                <xsl:for-each select="TransportInformationMessage/TransportUnits/TransportUnit">
                    <xsl:call-template name="transport"/>
                </xsl:for-each>
                <xsl:for-each select="TransportInformationMessage/Waybill/TransportUnits/TransportUnit">
                    <xsl:call-template name="transport"/>
                </xsl:for-each>
                <xsl:for-each select="TransportInformationMessage/Waybill">
                    <EdiImportTransportationDTO>
                        <Consignments>
                            <xsl:for-each select="Shipments/Shipment">
                                <xsl:call-template name="consignment"/>
                            </xsl:for-each>
                        </Consignments>
                        <EdiTerminalDepartureTime>
                            <xsl:value-of select="DatesAndTimes/EstimatedDepartureDateTime"/>
                            <xsl:value-of select="DatesAndTimes/DepartureDateTime"/>
                        </EdiTerminalDepartureTime>
                        <EdiAgentTerminalArrivalDate>
                            <xsl:value-of select="DatesAndTimes/EstimatedArrivalDateTime"/>
                            <xsl:value-of select="DatesAndTimes/ArrivalDateTime"/>
                        </EdiAgentTerminalArrivalDate>
                        <EdiActivevehicle>
                            <xsl:value-of select="Vehicle/TransportShiftNumber"/>
                        </EdiActivevehicle>
                        <EdiConveyerZipCodeTown><xsl:text> </xsl:text></EdiConveyerZipCodeTown>
                    </EdiImportTransportationDTO>
                </xsl:for-each>
            </Transportations>
        </InboundFargoMessage>
    </xsl:template>
</xsl:stylesheet>

Какие потребности быть добавленным, так, чтобы пустые элементы были не учтены?

Например, отрывок от получающегося xml:

<?xml version="1.0" encoding="UTF-8"?>
<InboundFargoMessage xmlns:p="http://tempuri.org/XMLSchema.xsd"
        xmlns:far="http://www.itella.com/fargo/fargogate/"
        xmlns:a="http://tempuri.org/XMLSchema.xsd">
    <EdiSender>XXXX</EdiSender>
    <EdiReceiver>YYYY</EdiReceiver>
    <EdiSource>TR/BAL/IST</EdiSource>
    <EdiDestination>FARGO</EdiDestination>
    <Transportations>
        <EdiImportTransportationDTO>
            <Consignments>
                <EdiImportConsignmentDTO>
                    <ConsignmentLines>
                        <EdiImportConsignmentLineDTO>
                            <DangerousGoodsItems>
                                <EdiImportDangerGoodsItemDTO>
                                    <EdiKolliTypeOuter/>
                                    <EdiKolliTypeInner/>
                                    <EdiTechnicalDescription/>
                                    <EdiUNno/>
                                    <EdiClass/>
                                    <EdiDangerFactor/>
                                    <EdiEmergencyTemperature/>
                                </EdiImportDangerGoodsItemDTO>
                            </DangerousGoodsItems>
                            <BarCodes>
                                <EdiImportConsignmentLineBarcodeDTO/>
                            </BarCodes>
                            <EdiNumberOfPieces>00000002</EdiNumberOfPieces>
                            <EdiGrossWeight>0.000</EdiGrossWeight>
                            <EdiHeight/>
                            <EdiWidth/>
                            <EdiLength/>
                            <EdiGoodsDescription/>
                            <EdiMarkingAndNumber/>
                            <EdiKolliType>road</EdiKolliType>
                            <EdiCbm/>
                            <EdiLdm/>
                        </EdiImportConsignmentLineDTO>

Это действительно должно быть:

<?xml version="1.0" encoding="UTF-8"?>
<InboundFargoMessage xmlns:p="http://tempuri.org/XMLSchema.xsd"
        xmlns:far="http://www.itella.com/fargo/fargogate/"
        xmlns:a="http://tempuri.org/XMLSchema.xsd">
    <EdiSender>XXXX</EdiSender>
    <EdiReceiver>YYYY</EdiReceiver>
    <EdiSource>TR/BAL/IST</EdiSource>
    <EdiDestination>FARGO</EdiDestination>
    <Transportations>
        <EdiImportTransportationDTO>
            <Consignments>
                <EdiImportConsignmentDTO>
                    <ConsignmentLines>
                        <EdiImportConsignmentLineDTO>
                            <DangerousGoodsItems/>
                            <BarCodes/>
                            <EdiNumberOfPieces>00000002</EdiNumberOfPieces>
                            <EdiGrossWeight>0.000</EdiGrossWeight>
                            <EdiKolliType>road</EdiKolliType>
                        </EdiImportConsignmentLineDTO>

Другими словами: Пустые элементы должны быть не учтены.

8
задан Fedor Steeman 24 April 2010 в 21:51
поделиться

3 ответа

Предоставленный (частичный) код XSLT хорошо иллюстрирует антипаттерн XSLT. Почти всегда старайтесь избегать использования .

Ниже приведен образец XML-документа и преобразование, которое копирует все узлы, за исключением «пустых» элементов. Здесь под «пустым» мы подразумеваем либо бездетный узел, либо дочерний узел с одним дочерним узлом, состоящим только из пробелов.

XML-документ :

<a>
 <b>
   <c>  </c>
   <d/>
   <e>1</e>
 </b>
</a>

Преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "*[not(node())]
  |
   *[not(node()[2])
   and
     node()/self::text()
   and
     not(normalize-space())
     ]
  "/>
</xsl:stylesheet>

Результат:

<a>
   <b>
      <e>1</e>
   </b>
</a>

Обратите внимание на :

  1. Использование правила идентификации .

  2. Как мы заменяем Правило идентичности шаблоном, который соответствует только «пустым» элементам. Поскольку этот шаблон ничего не делает (вообще не имеет тела), он не копирует («удаляет») «пустые» элементы.

Использование и переопределение правила идентификации является наиболее важным шаблоном проектирования XSLT.

11
ответ дан 5 December 2019 в 14:01
поделиться

Это, вероятно, самый простой способ:

<xsl:for-each select="Nodes/Node[text() != '']">

</xsl:for-each>

Если вы контролируете создание XML, не добавляйте корневой узел, если нет дочерних узлов. Независимо от того, какой способ вы выберете, XSL довольно многословен.

1
ответ дан 5 December 2019 в 14:01
поделиться

Есть несколько сложных случаев, когда ответ Дмитрия (который, безусловно, является правильным подходом) может повести себя неожиданно. Например, если вы рефакторизовали свой XSLT для использования шаблона идентичности (а это необходимо), и создали шаблон следующего вида:

<xsl:template match="Vehicle/TransportShiftNumber[. != '123']">
   <EdiActivevehicle>
      <xsl:value-of select="."/>
   </EdiActivevehicle> 
</xsl:template>

преобразование может по-прежнему создавать пустые элементы EdiActivevehicle, если TransportShiftNumber пуст.

Обычно, если несколько шаблонов соответствуют узлу, выбирается тот, который более специфичен. "Более специфичный" обычно означает, что шаблоны, имеющие предикат, побеждают шаблоны, не имеющие предиката. (Фактические правила разрешения конфликтов более сложны; см. раздел 5.5 рекомендаций XSLT). В данном случае и вышеприведенный шаблон, и шаблон пустого элемента используют предикаты, и поэтому оба имеют одинаковый приоритет.

Поэтому XSLT-процессор сделает одно из двух: сообщит об ошибке (это допустимо, хотя я никогда не видел настолько недружелюбного XSLT-процессора) или выберет шаблон, который появится последним в таблице стилей.

Есть два способа исправить это. Либо поместить шаблон, фильтрующий пустые элементы, в самый низ таблицы стилей, либо явно присвоить ему приоритет выше 0.5 (это значение по умолчанию для большинства шаблонов с предикатами):

Я бы, скорее всего, сделал последнее, потому что обычно структурирую таблицы стилей с расчетом на то, что порядок следования шаблонов не имеет значения, и не хочу неприятных сюрпризов, если начну что-то переставлять. Но я бы обязательно поместил туда комментарий с объяснением: Я никогда не видел, чтобы кто-то действительно использовал явный приоритет для шаблона.

0
ответ дан 5 December 2019 в 14:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: