#xslt
#xslt
Вопрос:
У меня есть следующая упрощенная структура XML:
<?xml version="1.0" encoding="UTF-8"?>
<ExportData>
<TransportHeader>
<Timestamp>2011-01-16 06:00:33</Timestamp>
<From>
<Name>DynamicExport</Name>
<Version>1.</Version>
</From>
<MessageId>d7b5c5b69a83</MessageId>
</TransportHeader>
<ExportConfig>
<DateTimeFormat>yyyy-MM-dd HH:mm:ss</DateTimeFormat>
<DecimalSymbol>.</DecimalSymbol>
</ExportConfig>
<DataSet>
<Tables>
<Table>
<RH>...</RH>
<Rows>
<R>Data1</R>
<R>Data2</R>
<R>Data3</R>
<R>Data4</R>
<R>Data5</R>
</Rows>
</Table>
</Tables>
</DataSet>
</ExportData>
Я должен проверить, существуют <R>
элементы или нет. Если никаких <R>
элементов не существует, сопоставление должно быть прервано, в противном случае необходимо создать <Line>
элемент для <R>
каждого.
Я придумал это решение, которое пока работает отлично:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />
<!-- suppress nodes that are not matched -->
<xsl:template match="text() | @*">
<xsl:apply-templates select="text() | @*"/>
</xsl:template>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="not(ExportData/DataSet/Tables/Table/Rows/node())">
<xsl:message terminate="yes">No line items</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows">
<INVOIC02>
<!-- apply LINE ITEMS template -->
<xsl:apply-templates select="R"/>
</INVOIC02>
</xsl:template>
<!-- Template creating LINE ITEMS -->
<xsl:template match="R">
<Line>
<elements></elements>
</Line>
</xsl:template>
</xsl:stylesheet>
Если есть <R>
элементы, результат будет таким:
<?xml version="1.0" encoding="ISO-8859-1"?>
<INVOIC02>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
<Line>
<elements/>
</Line>
</INVOIC02>
Если есть только <Rows/>
и нет <R>
s, сопоставление прерывается.
Теперь у меня есть два вопроса:
-Надежен ли мой тест на <R>
элементы: test="not(ExportData/DataSet/Tables/Table/Rows/node())"
?
-Я использую <xsl:apply-templates>
для создания <Line>
элементов вместо <xsl:for-each>
конструкции. Мои выражения XPath в порядке или я мог бы сделать их лучше?
Ответ №1:
Надежен ли мой тест для элементов: test=»not(exportData / DataSet / Tables / Таблица / Строки / узел())»?
Ну, вы хотите, чтобы он завершался сбоем, если в нем нет R
элементов, или завершался сбоем, если Rows
у него нет дочернего узла node()
, который включал бы любой элемент (не только R
), text()
, comment()
или processing-instruction()
?
Если вы действительно хотите убедиться, что существует хотя бы один R
элемент, который является дочерним для Rows
, вам следует скорректировать критерии тестирования, чтобы они были более конкретными:
test="not(ExportData/DataSet/Tables/Table/Rows/R)"
В противном случае он может пройти этот тест и продолжить обработку, а не сгенерировать нужный вам контент.
I am using <xsl:apply-templates> to create the <Line> items instead of an <xsl:for-each> construct. Are my XPath expressions okay or could I make them better?
Вы могли бы избавиться от <xsl:if>
условной логики внутри вашего шаблона для корневого узла и переместить эту логику в шаблон для, Rows
который не содержит R
дочерних элементов. Включение логики в xsl:template
@match
критерии упрощает оптимизацию процессоров XSLT, что может привести к увеличению производительности.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="ISO-8859-1" method="xml" indent="yes" />
<!-- suppress nodes that are not matched -->
<xsl:template match="text() | @*">
<xsl:apply-templates select="text() | @*"/>
</xsl:template>
<!--All Rows must contain an R.
If we encounter any that do not, terminate the transform -->
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows[not(R)]">
<xsl:message terminate="yes">No line items</xsl:message>
</xsl:template>
<!--match for Rows that have R children -->
<xsl:template match="/ExportData/DataSet/Tables/Table/Rows[R]">
<INVOIC02>
<!-- apply LINE ITEMS template -->
<xsl:apply-templates select="R"/>
</INVOIC02>
</xsl:template>
<!-- Template creating LINE ITEMS -->
<xsl:template match="R">
<Line>
<elements></elements>
</Line>
</xsl:template>
</xsl:stylesheet>
Ответ №2:
Это проверит, имеет ли R-узел дочерний элемент:
<xsl:if test="R">
<!--What you want to do here-->
</xsl:if>