1 Вопрос: Как исправить проблему с картами XSLT 3.0?

вопрос создан в Wed, May 8, 2019 12:00 AM

Я беру в качестве входного файла XML-файл, который содержит данные о сотруднике и значения сопоставления, т. е. идентификатор семейства заданий и имя семейства заданий. Поэтому, когда у сотрудника совпадает идентификатор семейства заданий, мы заменяем имя семейства заданий в Worker_Data, а остальные элементы в Worker_Data совпадают. Поэтому я использовал совпадение идентификаторов, а затем вызвал элемент, значение которого необходимо заменить. Но это дает мне бланк для фамилии работы.

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

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday/bsvc" exclude-result-prefixes="xs" version="3.0">

    <xsl:mode streamable="no" on-no-match="shallow-skip" use- accumulators="JobFamilyLookup CurrentLookupValue" />

    <xsl:output method="xml" />

    <xsl:accumulator name="CurrentLookupValue" as="xs:string" initial- value="''" streamable="no">
        <xsl:accumulator-rule match="wd:JobFamilyID/text()" select="string()" />
    </xsl:accumulator>

    <xsl:accumulator name="JobFamilyLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="no">
        <xsl:accumulator-rule match="wd:JobFamilyName/text()" select="map:put($value, accumulator- 
    before('CurrentLookupValue'),string(.))" />
    </xsl:accumulator>

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

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

    <xsl:template match="wd:Job_Family_ID">
        <xsl:copy>
            <xsl:value-of select="accumulator-before('JobFamilyLookup') ( 
        normalize-space( wd:Job_Family_ID ) )" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="wd:JobFamilyGroupDetails">

    </xsl:template>
</xsl:stylesheet>

Input:

<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
    <wd:EmpID>50001</wd:EmpID>
    <wd:Job_Title>Global Talent Director</wd:Job_Title>
    <wd:Job_Family_ID>TAL_TALENT_ACQUISITION</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
    <wd:EmpID>50000</wd:EmpID>
    <wd:Job_Title>Executive Assistant</wd:Job_Title>
    <wd:Job_Family_ID>ADMIN_EXECUTIVE_ASSISTANT</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:JobFamilyGroupDetails>
    <wd:JobFamilyDetails>
        <wd:JobFamilyID>ADMIN_EXECUTIVE_ASSISTANT</wd:JobFamilyID>
        <wd:JobFamilyName>ADMIN - Executive Assistant</wd:JobFamilyName>
    </wd:JobFamilyDetails>
    <wd:JobFamilyDetails>
        <wd:JobFamilyID>TAL_TALENT_ACQUISITION</wd:JobFamilyID>
        <wd:JobFamilyName>TAL - Talent Acquisition</wd:JobFamilyName>
    </wd:JobFamilyDetails>
   </wd:JobFamilyGroupDetails>
</wd:test>

Ожидаемый результат:

<?xml version="1.0" encoding="UTF-8"?>
<wd:test xmlns:wd="urn:com.workday/bsvc">
<wd:Worker_Data>
    <wd:EmpID>50001</wd:EmpID>
    <wd:Job_Title>Global Talent Director</wd:Job_Title>
    <wd:Job_Family_ID>TAL - Talent Acquisition</wd:Job_Family_ID>
</wd:Worker_Data>
<wd:Worker_Data>
    <wd:EmpID>50000</wd:EmpID>
    <wd:Job_Title>Executive Assistant</wd:Job_Title>
    <wd:Job_Family_ID>ADMIN - Executive Assistant</wd:Job_Family_ID>
</wd:Worker_Data>
</wd:test>
    
0
1 ответ                              1                         

Я бы просто использовал ключ:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xpath-default-namespace="urn:com.workday/bsvc"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:key name="details" match="JobFamilyDetails" use="JobFamilyID"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="Worker_Data/Job_Family_ID[key('details', .)]">
      <xsl:copy>{key('details', .)/JobFamilyName}</xsl:copy>
  </xsl:template>

  <xsl:template match="JobFamilyGroupDetails"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ncdD7mJ

Что касается вашего запроса об использовании потоковой передачи и аккумуляторов, так как потоковая передача работает вперед, то единственный единственный способ решить эту проблему - сохранить соответствующие рабочие данные в последовательности карт, а затем записать подробные данные на карту по мере того, как вы попытался использовать его в качестве параметра в шаблоне для каждого элемента в последовательности карты рабочих данных, которая выводит соответствующий элемент:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:wd="urn:com.workday/bsvc"
    xpath-default-namespace="urn:com.workday/bsvc"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>

    <xsl:output method="xml" indent="yes"/>

    <xsl:accumulator name="current-id" as="xs:string?" initial-value="()" streamable="yes">
        <xsl:accumulator-rule match="JobFamilyDetails/JobFamilyID/text()"
            select="string()"/>
    </xsl:accumulator>

    <xsl:accumulator name="details" as="map(xs:string, xs:string)" initial-value="map{}" streamable="yes">
        <xsl:accumulator-rule match="JobFamilyDetails/JobFamilyName/text()"
            select="map:put($value, accumulator-before('current-id'), string())"/>
    </xsl:accumulator>

    <xsl:accumulator name="workers" as="map(xs:string, xs:string)*" initial-value="()" streamable="yes">
        <xsl:accumulator-rule match="Worker_Data" select="$value, map { }"/>
        <xsl:accumulator-rule match="Worker_Data/EmpID/text()" 
            select="let $wmap := $value[last()]
            return ($value[position() lt last()], map:put($wmap, 'id', string()))"/>
        <xsl:accumulator-rule match="Worker_Data/Job_Title/text()" 
            select="let $wmap := $value[last()]
            return ($value[position() lt last()], map:put($wmap, 'title', string()))"/>
        <xsl:accumulator-rule match="Worker_Data/Job_Family_ID/text()" 
            select="let $wmap := $value[last()]
            return ($value[position() lt last()], map:put($wmap, 'jfid', string()))"/>
    </xsl:accumulator>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates/>
            <xsl:apply-templates select="accumulator-after('workers')" mode="output">
                <xsl:with-param name="details" select="accumulator-after('details')"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match=".[. instance of map(*)]" mode="output" expand-text="yes">
        <xsl:param name="details"/>
        <wd:Worker_Data>
            <wd:EmpID>{?id}</wd:EmpID>
            <wd:Job_Title>{?title}</wd:Job_Title>
            <wd:Job_Family_ID>{$details(?jfid)}</wd:Job_Family_ID>
        </wd:Worker_Data>      
    </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifpL/2 р>

Хорошо ли это работает с точки зрения использования памяти, которую я не проверял.

    
1
2019-05-09 09: 14: 51Z
  1. Спасибо, Мартин, я хочу сделать этот код как streamabl. Вот почему я пришел к концепции карты в XSLT3.0. Я сделал Streamable как нет в приведенном выше фрагменте, но я включу, когда я помещаю код в приложение. Извините, что запутали вас, ребята.
    2019-05-08 16: 11: 37Z
  2. Потоковая передача работает только вперед, поэтому я не вижу пути, учитывая вашу структуру ввода, где JobFamilyDetails хранятся после Worker_Data, чтобы использовать потоковую передачу для доступа к деталям при обработке рабочие данные. Вам потребуется обработать ввод дважды, чтобы сохранить детали после первой обработки и сделать их доступными во время второй обработки рабочих данных.
    2019-05-08 16: 19: 55Z
  3. Спасибо за объяснение, Мартин. Я все еще изучаю XSLT и действительно не знаю об этой процедуре потоковой передачи. Если вы не возражаете, предложите мне книгу или сайт, чтобы изучить и понять материал XSLT 3.0.
    2019-05-08 16: 26: 24Z
  4. Что ж, раздел StackOverflow в XSLT 3 stackoverflow.com/tags /xslt-3.0/info содержит множество ссылок на спецификации и материалы, а также на разделы по XSLT в целом и версию XSLT 2 stackoverflow.com/tags/xslt-2.0/info , что, несомненно, также поможет, если вы новичок в XSLT в целом. Я не уверен, что есть какая-либо книга, посвященная XSLT 3, но Saxonica в документации Saxon рассматривает все, что связано с XSLT и XPath saxonica.com/html/documentation/using-xsl/xslt30.html . Другой поставщик, Altova, также имеет раздел, посвященный XPath 3 altova.com/training/xpath3 .
    2019-05-08 21: 05: 48Z
  5. Большое спасибо, Мартин. Это определенно поможет мне выделить.
    2019-05-08 21: 13: 15Z
источник размещен Вот