Как проверить существование атрибута XML с помощью XSLT - PullRequest
0 голосов
/ 19 февраля 2010

О недельном возрасте Я задал вопрос здесь и получил большую помощь. Теперь у моего вопроса есть продолжение. Первоначально мне пришлось конвертировать XML в текстовый файл. Вот пример XML-файла:

<DOC xsi:noNamespaceSchemaLocation="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DOC_REQUISITES DOC_DATE="2009-04-23" DOC_NO="99999999"/>
<DOCID TradeDate="2009-04-23" Weekday="Monday" MainFirmId="ZXC0000" FirmName="Firm Name" FirmINN="1234567899">
    <FIRM FirmID="FirmId">
        <CURRENCY CurrencyId="USD">
        <DEPARTMENT DepartmentId="ABCD" DepName="Department Name1">
            <SETTLEDATE SettleDate="2009-04-23">
                <SECURITY SecurityId="QAZ" SecShortName="SecName1" SecurityType="dc" FaceValue="5">
                    <TRDACC TrdAccId="ABC00000">
                        <RECORDS RecNo="1" TradeNo="111" TradeTime="15:15:16" Price="10" Quantity="50" Value="500"/>
                    </TRDACC>
                    <TRDACC TrdAccId="SDC00000">
                        <RECORDS RecNo="2" TradeNo="112" TradeTime="15:15:16" Price="10" Quantity="50" Value="500"/>
                        <RECORDS RecNo="3" TradeNo="113" TradeTime="15:15:16" Price="20" Quantity="10" Value="200"/>
                    </TRDACC>
                </SECURITY>
                <SECURITY SecurityId="WSX" SecShortName="SecName2" SecurityType="dc" FaceValue="1">
                    <TRDACC TrdAccId="ABC00000">
                        <RECORDS RecNo="4" TradeNo="114" TradeTime="15:15:13" Price="2" Quantity="1" Value="2"/>
                    </TRDACC>
                </SECURITY>
            </SETTLEDATE>
        </DEPARTMENT>
        <DEPARTMENT DepartmentId="CBSD" DepName="Department Name2">
            <SETTLEDATE SettleDate="2009-05-20">
                <SECURITY SecurityId="RFV" SecShortName="SecName3" SecurityType="dc" FaceValue="2">
                    <TRDACC TrdAccId="SDC00000">
                        <RECORDS RecNo="5" TradeNo="115" TradeTime="15:15:13" Price="100" Quantity="10" Value="1000"/>
                    </TRDACC>
                </SECURITY>
            </SETTLEDATE>
        </DEPARTMENT>
    </CURRENCY>
  </FIRM>
</DOCID>

Мой желаемый вывод выглядит так:

2009-04-23,99999999,2009-04-23,Monday,ZXC0000,Firm Name,1234567899,FirmId,USD,ABCD,Department Name1,2009-04-23,QAZ,SecName1,dc,5,ABC00000,1,111,15:15:16,10,50,500
2009-04-23,99999999,2009-04-23,Monday,ZXC0000,Firm Name,1234567899,FirmId,USD,ABCD,Department Name1,2009-04-23,QAZ,SecName1,dc,5,SDC00000,2,112,15:15:16,10,50,500
2009-04-23,99999999,2009-04-23,Monday,ZXC0000,Firm Name,1234567899,FirmId,USD,ABCD,Department Name1,2009-04-23,QAZ,SecName1,dc,5,SDC00000,3,113,15:15:16,20,10,200
2009-04-23,99999999,2009-04-23,Monday,ZXC0000,Firm Name,1234567899,FirmId,USD,ABCD,Department Name1,2009-04-23,WSX,SecName2,dc,1,ABC00000,4,114,15:15:13,2,1,2
2009-04-23,99999999,2009-04-23,Monday,ZXC0000,Firm Name,1234567899,FirmId,USD,CBSD,Department Name2,2009-05-20,RFV,SecName3,dc,2,SDC00000,5,115,15:15:13,100,10,1000

Этот XSLT был опубликован для меня, и он прекрасно работает. Я действительно ценю это.

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

    <xsl:template match="/">
       <xsl:apply-templates select="/DOC/DOCID/FIRM/CURRENCY/DEPARTMENT/SETTLEDATE/SECURITY/TRDACC"/>
    </xsl:template>

<xsl:template match="TRDACC">
    <!--Select all of the attribute values from the preceding DOC_REQUISITES attibutes, TRDACC ancestor elements, the current element, and all of it's descendants and then apply-templates to those attributes -->
    <xsl:apply-templates select="preceding::DOC_REQUISITES/@* | ancestor::*[not(local-name()='DOC')]/@* | @* | descendant::*/@*"/>
    <!--Adds a carriage return at the end of the line -->
    <xsl:value-of select="'&#10;'"/>
</xsl:template>

<!--Template match for attributes that emits the attribute value and a ',', except for the last one -->
<xsl:template match="@*[.!='']">
    <xsl:value-of select="."/>
    <xsl:if test="position()!=last()">,</xsl:if>
</xsl:template>

</xsl:stylesheet>

Вот мой вопрос: Полученный выходной файл позже будет загружен в базу данных. Столбцы таблицы соответствуют атрибутам файла xml. В некоторых столбцах допускается Null. Это означает, что некоторые атрибуты могут быть опущены. Например, если attr. DOC_NO, Weekday, SettleDate, RecNo отсутствует, выходная запись должна выглядеть так:

2009-04-23,,2009-04-23,,ZXC0000,Firm Name,1234567899,FirmId,USD,ABCD,Department Name1,,QAZ,SecName1,dc,5,ABC00000,,111,15:15:16,10,50,500

Другими словами, мне нужно проверить наличие каждого атрибута. Я пытаюсь решить это, но мои знания xslt очень ограничены. Пожалуйста, помогите мне. Благодарю.

Ответы [ 4 ]

1 голос
/ 20 февраля 2010

Предыдущая версия таблицы стилей основывалась на структуре XML-документа для управления большой частью вывода, часто называемого методом push .

Если вы не уверены, что у вас есть какие-то атрибуты, вы можете использовать таблицу стилей, которая больше похожа на ' pull ', и специально запрашивать определенные атрибуты в определенном порядке:

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

    <xsl:template match="/">
       <xsl:apply-templates select="/DOC/DOCID/FIRM/CURRENCY/DEPARTMENT/SETTLEDATE/SECURITY/TRDACC"/>
    </xsl:template>

<xsl:template match="TRDACC">
    <xsl:value-of select="preceding::DOC_REQUISITES/@DOC_DATE"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="preceding::DOC_REQUISITES/@DOC_NO"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DOCID/@TradeDate"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DOCID/@Weekday"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DOCID/@MainFirmId"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DOCID/@FirmName"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DOCID/@FirmINN"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::FIRM/@FirmID"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::CURRENCY/@CurrencyId"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DEPARTMENT/@DepartmentId"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::DEPARTMENT/@DepName"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::SETTLEDATE/@SettleDate"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::SECURITY/@SecurityId"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::SECURITY/@SecShortName"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::SECURITY/@SecurityType"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="ancestor::SECURITY/@FaceValue"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="@TrdAccId"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@RecNo"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@TradeNo"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@TradeTime"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@Price"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@Quantity"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="RECORDS/@Value"/>
    <xsl:text>&#10;</xsl:text>

</xsl:template>

</xsl:stylesheet>

Если атрибут не существует, то он ничего не выбирает для значения и оставляет пустое место между запятыми.

0 голосов
/ 20 февраля 2010

Джим, спасибо за ответ. (Я не уверен, где написать ответ).

Я думаю, что должен сделать что-то подобное для каждого возможного атрибута:

<xsl:choose>
    <xsl:when test="@Weekday">
        <xsl:value-of select="@Weekday"/>
        <xsl:text>,</xsl:text>
    </xsl:when>
    <xsl:otherwise>
        <xsl:text>,</xsl:text>
    </xsl:otherwise>
</xsl:choose>

Таким образом, если он существует, он помещает значение в запись, если не просто ",". Но я не знаю, как встроить это в XSLT, который у меня уже есть.

Что вы предлагаете работать, если какой-либо атрибут = "" , но мне нужно проверить наличие атрибутов, потому что есть список возможных атрибутов, который соответствует столбцам таблицы, и входной файл XML просто может не иметь их всех. - клипа 3 часа назад [удалить этот комментарий]

0 голосов
/ 20 февраля 2010

Поскольку выходные данные будут загружены в базу данных, важен порядок столбцов в выходных данных.

Поскольку строковое значение пустого набора узлов является пустой строкой, проверка существования какого-либо атрибута не требуется.

Я произвел вывод по-разному в DOCID и SECURITY, использую стиль, который кажется вам чище.

Я также добавил xsl: strip-space, чтобы игнорировать пробелы во входном документе.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="RECORDS">
      <xsl:apply-templates select="ancestor::DOCID" mode="print" />
      <xsl:apply-templates select="ancestor::FIRM" mode="print" />
      <xsl:apply-templates select="ancestor::FIRM/CURRENCY" mode="print" />
      <xsl:apply-templates select="ancestor::DEPARTMENT" mode="print" />
      <xsl:apply-templates select="ancestor::SETTLEDATE" mode="print" />
      <xsl:apply-templates select="ancestor::SECURITY" mode="print" />
      <xsl:apply-templates select="ancestor::TRDACC" mode="print" />

      <xsl:value-of select="@RecNo" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@TradeNo" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@TradeTime" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@Price" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@Quantity" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@Value" />
      <xsl:text>&#10;&#13;</xsl:text>

    </xsl:template>

    <xsl:template match="DOCID" mode="print">
      <xsl:value-of select="@TradeDate" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@Weekday" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@WMainFirmId" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@FirmName" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="@WFirmINN" />
      <xsl:text>,</xsl:text>
    </xsl:template>

    <xsl:template match="SECURITY" mode="print">
      <xsl:value-of select="concat(@SecurityId,',',@SecShortName,',',@SecurityType,',',@FaceValue,',')" />
    </xsl:template>

    <!-- etc for each element we apply in the RECORD template -->

</xsl:stylesheet>
0 голосов
/ 20 февраля 2010

Без подробного анализа, я думаю, все, что вам нужно сделать, это изменить последний шаблон и удалить непустой тест [.!=''], чтобы он выглядел следующим образом

<xsl:template match="@*">
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...