2017-02-03 22 views
0

У меня есть XML, который должен быть преобразован XSLT 1.0. Папка XML «Поля» определяет порядок имен для каждого элемента «Row». Таким образом, MaterialCode в каждой папке «Row» имеет первую позицию, StorageMatCode занимает второе место, а «Сумма» - третье. Мне нужно удалить все дубликаты «MaterialCode», но поместить все «Суммы» в один. Входной XML:Выбор отдельных узлов и общей суммы из xml с помощью xslt 1.0

<Response xmlns="http://www.sample.ru/sample/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<Header> 
    <ObjectType>StorageMats</ObjectType> 
    <Version>1.0.0</Version> 
    <Fields> 
     <Field type="decimal">MaterialCode</Field> 
     <Field type="decimal">StorageMatCode</Field> 
     <Field type="decimal">Amount</Field> 
    </Fields> 
</Header> 
<Body> 
    <Row> 
     <FieldValue>475625947</FieldValue> 
     <FieldValue>456789</FieldValue> 
     <FieldValue>1000</FieldValue> 
    </Row> 
    <Row> 
     <FieldValue>804685387</FieldValue> 
     <FieldValue>273456</FieldValue> 
     <FieldValue>3047</FieldValue> 
    </Row> 
    <Row> 
     <FieldValue>973681347</FieldValue> 
     <FieldValue>578357</FieldValue> 
     <FieldValue>2037</FieldValue> 
    </Row> 
    <Row> 
     <FieldValue>804685387</FieldValue> 
     <FieldValue>273456</FieldValue> 
     <FieldValue>5000</FieldValue> 
    </Row> 
</Body> 
</Response> 

Я хочу, чтобы получить этот XML:

<?xml version="1.0" encoding="UTF-8"?> 
<BDStorageMats xmlns="http://www.sample.ru/sample/BDStorageMats/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <BDStorageMat> 
     <MaterialCode>475625947</MaterialCode> 
     <Amount>1000</Amount> 
    </BDStorageMat> 
    <BDStorageMat> 
     <MaterialCode>804685387</MaterialCode> 
     <Amount>8047</Amount> 
    </BDStorageMat> 
    <BDStorageMat> 
     <MaterialCode>973681347</MaterialCode> 
     <Amount>2037</Amount> 
    </BDStorageMat> 
</BDStorageMats> 

Я создал этот XSLT:

<xsl:stylesheet version="1.0" xmlns="http://www.sample.ru/sample/BDStorageMats/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/> 
<xsl:key match="*[local-name()= 'Response']/*[local-name()= 'Body']/*[local-name()= 'Row']" name="codeDistinct" use="*[local-name()= 'FieldValue'][count(*[local-name()= 'Response']/*[local-name()= 'Header']/*[local-name()= 'Fields']/*[local-name()= 'Field'][.='MaterialCode']/preceding-sibling::*)+1]"/> 
<xsl:template match="/"> 
    <BDStorageMats> 
     <xsl:variable name="amountPosition" select="count(*[local-name()= 'Response']/*[local-name()= 'Header']/*[local-name()= 'Fields']/*[local-name()= 'Field'][.='Amount']/preceding-sibling::*)+1"/> 
     <xsl:variable name="materialCodePosition" select="count(*[local-name()= 'Response']/*[local-name()= 'Header']/*[local-name()= 'Fields']/*[local-name()= 'Field'][.='MaterialCode']/preceding-sibling::*)+1"/> 
     <xsl:for-each select="*[local-name()= 'Response']/*[local-name()= 'Body']/*[local-name()= 'Row'][generate-id() = generate-id(key('codeDistinct', *[local-name()= 'FieldValue'][count(*[local-name()= 'Response']/*[local-name()= 'Header']/*[local-name()= 'Fields']/*[local-name()= 'Field'][.='MaterialCode']/preceding-sibling::*)+1]))[1]]"> 
      <xsl:variable name="keyGroup" select="key('codeDistinct', *[local-name()= 'FieldValue'][count(*[local-name()= 'Response']/*[local-name()= 'Header']/*[local-name()= 'Fields']/*[local-name()= 'Field'][.='MaterialCode']/preceding-sibling::*)+1])"/> 
      <BDStorageMat> 
       <MaterialCode> 
        <xsl:value-of select="(*[local-name()= 'FieldValue'])[$materialCodePosition]"/> 
       </MaterialCode> 
       <Amount> 
        <xsl:value-of select="sum($keyGroup/(*[local-name()= 'FieldValue'])[$amountPosition])"/> 
       </Amount> 
      </BDStorageMat> 
     </xsl:for-each> 
    </BDStorageMats> 
</xsl:template> 
</xsl:stylesheet> 

И это прекрасно работает в Altova, но моя система использует Apache Xalan Processor для XSLT a го он отказывается эта линия от XSLT:

<Amount> 
    <xsl:value-of select="sum($keyGroup/(*[local-name()= 'FieldValue']) [$amountPosition])"/> 
</Amount> 

есть ли другой способ сделать то, что я хочу с помощью XSLT 1.0?

ответ

2

Если вы используете Xalan (или другой процессор, который поддерживает функцию расширения EXSLT set:distinct()), вы можете сделать:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ns1="http://www.sample.ru/sample/" 
xmlns:set="http://exslt.org/sets" 
exclude-result-prefixes="ns1 set"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:key name="row" match="ns1:Row" use="ns1:FieldValue[1]" /> 

<xsl:template match="/ns1:Response"> 
    <BDStorageMats xmlns="http://www.sample.ru/sample/BDStorageMats/1.0"> 
     <xsl:for-each select="set:distinct(ns1:Body/ns1:Row/ns1:FieldValue[1])"> 
      <BDStorageMat> 
       <MaterialCode> 
        <xsl:value-of select="." /> 
       </MaterialCode> 
       <Amount> 
        <xsl:value-of select="sum(key('row', .)/ns1:FieldValue[3])" /> 
       </Amount> 
      </BDStorageMat> 
     </xsl:for-each> 
    </BDStorageMats> 
</xsl:template> 

</xsl:stylesheet> 

Обратите внимание на использование префикса для выбора узлов во входном XML правильно.

 Смежные вопросы

  • Нет связанных вопросов^_^