Выражение фильтра XSLT XPATH во время XSL: выберите
У меня есть следующий XML и мне нужно условно отфильтровать, имеет ли значение UnitOfMeasure. Если первый UnitOfMeasure, где ID = 'AcceptanceCriterionValue1' содержит строку длиной более 0, я должен выбрать это значение. В противном случае мне нужно выбрать значение узла UnitOfMeasure, где ID = 'AcceptanceCriterionValue2'. Другими словами, если pH1 существует, возьмите его. В противном случае захватить pH2:
`
<MaterialLots>
<MaterialLotProperty>
<ID>AcceptanceCriterionValue1</ID>
<Value>
<ValueString>5</ValueString>
<UnitOfMeasure>pH1</UnitOfMeasure>
</Value>
</MaterialLotProperty>
<MaterialLotProperty>
<ID>AcceptanceCriterionValue2</ID>
<Value>
<ValueString>7</ValueString>
<UnitOfMeasure>pH2</UnitOfMeasure>
</Value>
</MaterialLotProperty>
</MaterialLots>
`
И мне нужно выполнить следующую логику. Первый оператор xsl:when успешно выполняется, когда pH1 существует, но если он пуст, xsl: в противном случае срабатывает, но по какой-то причине не возвращает pH2:
`
<xsl:choose>
<xsl:when test="ns:MaterialLots/ns:MaterialLotProperty/ns:ID='AcceptanceCriterionValue1' and string-length(ns:MaterialLots/ns:MaterialLotProperty/ns:Value/ns:UnitOfMeasure) > 0">
<xsl:value-of select="ns:MaterialLots/ns:MaterialLotProperty/ns:Value/ns:UnitOfMeasure" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="ns:MaterialLots/ns:MaterialLotProperty/ns:ID='AcceptanceCriterionValue2' and string-length(ns:MaterialLots/ns:MaterialLotProperty/ns:Value/ns:UnitOfMeasure) > 0">
<xsl:value-of select="ns:MaterialLots/ns:MaterialLotProperty/ns:Value/ns:UnitOfMeasure" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
`
3 ответа
Мне нужно выполнить следующую логику. Первый оператор xsl:when успешно выполняется, когда pH1 существует, но если он пуст, xsl: в противном случае срабатывает, но по какой-то причине не возвращает pH2
В общем, выражение XPath, которое выбирает узел $n1
когда условие $cond
удовлетворен и выбирает узел $n2
в противном случае это:
$n1[$cond] | $n2[not($cond)]
Применяется в вашем конкретном случае, мы заменяем $n1
с:
/*/MaterialLotProperty[ID='AcceptanceCriterionValue1']/Value/UnitOfMeasure
а также $cond
с:
text()
А также $n2
с:
/*/MaterialLotProperty[ID='AcceptanceCriterionValue2']/Value/UnitOfMeasure
Таким образом, можно использовать одно выражение XPath для выбора нужного узла:
/*/MaterialLotProperty[ID='AcceptanceCriterionValue1']/Value/UnitOfMeasure[text()]
|
/*/MaterialLotProperty[ID='AcceptanceCriterionValue2']/Value/UnitOfMeasure
[not(/*/MaterialLotProperty[ID='AcceptanceCriterionValue1']
/Value/UnitOfMeasure[text()])]
Используйте это единственное выражение XPath в этом простом преобразовании:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select=
"/*/MaterialLotProperty[ID='AcceptanceCriterionValue1']/Value/UnitOfMeasure[text()]
|
/*/MaterialLotProperty[ID='AcceptanceCriterionValue2']/Value/UnitOfMeasure
[not(/*/MaterialLotProperty[ID='AcceptanceCriterionValue1']
/Value/UnitOfMeasure[text()])]
"/>
</xsl:template>
</xsl:stylesheet>
Когда преобразование применяется к предоставленному документу XML:
<MaterialLots>
<MaterialLotProperty>
<ID>AcceptanceCriterionValue1</ID>
<Value>
<ValueString>5</ValueString>
<UnitOfMeasure>pH1</UnitOfMeasure>
</Value>
</MaterialLotProperty>
<MaterialLotProperty>
<ID>AcceptanceCriterionValue2</ID>
<Value>
<ValueString>7</ValueString>
<UnitOfMeasure>pH2</UnitOfMeasure>
</Value>
</MaterialLotProperty>
</MaterialLots>
желаемый, правильный результат получается:
pH1
Если вы замените в документе XML
<UnitOfMeasure>pH1</UnitOfMeasure>
с:
<UnitOfMeasure/>
опять правильный результат получается:
pH2
Вам нужно будет перебирать каждый объект MaterialLotProperty. Также проверьте длину UnitOfMeasure перед выбором.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="foo">
<xsl:output method="xml"/>
<xsl:template match="/">
<xml>
<xsl:for-each select='//ns:MaterialLotProperty'>
<xsl:if test='string-length(ns:Value/ns:UnitOfMeasure) > 0'>
<xsl:element name='output'>
<xsl:choose>
<xsl:when test="(ns:ID='AcceptanceCriterionValue1')">
<xsl:value-of select='ns:Value/ns:UnitOfMeasure'/>
</xsl:when>
<xsl:when test="(ns:ID='AcceptanceCriterionValue2')">
<xsl:value-of select='ns:Value/ns:UnitOfMeasure'/>
</xsl:when>
</xsl:choose>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>
Этот второй XSL выводит первый непустой UnitOfMeasure.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="foo">
<xsl:output method="xml"/>
<xsl:template match="/">
<xml>
<xsl:for-each select='//ns:MaterialLotProperty/ns:Value[string-length( ns:UnitOfMeasure ) > 0]/ns:UnitOfMeasure'>
<xsl:if test='(position() =1)'>
<xsl:element name='output'>
<xsl:value-of select='.'/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>
Выражение для проверки вашей первой меры это...
<xsl:when test="string-length(ns:MaterialLots/ns:MaterialLotProperty[ns:ID='AcceptanceCriterionValue1']/ns:Value/ns:UnitOfMeasure) > 0">
Однако было бы немного лучше использовать переменную, чтобы избежать некоторого повторения.
<xsl:variable name="uom1" select="ns:MaterialLots/ns:MaterialLotProperty[ns:ID='AcceptanceCriterionValue1']/ns:Value/ns:UnitOfMeasure" />
<xsl:choose>
<xsl:when test="string-length($uom1) > 0">
<xsl:value-of select="$uom1" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="ns:MaterialLots/ns:MaterialLotProperty[ns:ID='AcceptanceCriterionValue2']/ns:Value/ns:UnitOfMeasure" />
</xsl:otherwise>
</xsl:choose>
В качестве альтернативы, вы можете использовать xsl:key
<xsl:key name="MLP" match="ns:UnitOfMeasure" use="../../ns:ID" />
Тогда вы могли бы сделать это
<xsl:choose>
<xsl:when test="string-length(key('MLP', 'AcceptanceCriterionValue1')) > 0">
<xsl:value-of select="key('MLP', 'AcceptanceCriterionValue1')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="key('MLP', 'AcceptanceCriterionValue2')" />
</xsl:otherwise>
</xsl:choose>