Итерация с токенизацией - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть документ с 800 письмами к Уильяму и от него, упрощенно подобный этому:

 <?xml version="1.0" encoding="UTF-8"?>
<root>
    <TEI xml:id="1">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
            </correspAction>
            <correspAction type="received">
                <persName key="anna"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="2">
        <correspDesc>
            <correspAction type="sent">
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="3">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
            </correspAction>
            <correspAction type="received">
                <persName key="bertram"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="4">
        <correspDesc>
            <correspAction type="sent">
                <persName key="charlotte"/>
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="5">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
                <persName key="charlotte"/>
                <persName key="bertram"/>
            </correspAction>
            <correspAction type="received">
                <persName key="anna"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="6">
        <correspDesc>
            <correspAction type="sent">
                <persName key="abraham"/>
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
    <TEI xml:id="7">
     <correspDesc>
        <correspAction type="sent">
            <persName key="abraham"/>
            <persName key="william"/>
        </correspAction>
        <correspAction type="received">
            <persName key="charlotte"/>
        </correspAction>
       </correspDesc>
    </TEI>
</root>

Я хочу извлечь отдельные соответствия (Анна и ее секретарь Авраам принадлежат друг другу, Бертрам, Шарлотта).

Выходные данные должны: 1) записать имя основного корреспондента в элемент TEI (то есть @respondence = "anna", даже если письмо от Авраама)

2) копировать все письма по переписке, то есть все из анны и авраама, потом бертрам, потом шарлотту

3) когда (как в письме 5) Уильям и шарлотта пишут вместе анне, это письмо принадлежит только в переписке анны, но нев шарлотках

Пока у меня есть это:

<?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"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" encoding="utf-8" indent="no"/>

    <xsl:param name="persons">anna-abraham bertram charlotte</xsl:param> <!-- A dash marks correspondences belonging together -->

    <xsl:template match="root">
        <root>
            <xsl:variable name="ruth" select="." as="node()"/>
            <xsl:for-each select="tokenize($persons,' ')">
                <xsl:variable name="correspondents" select="." as="xs:string"/>
                <xsl:variable name="corr-main" select="tokenize($correspondents, '-')[1]" as="xs:string"/>
                <xsl:for-each select="tokenize($correspondents, '-')">
                <xsl:variable name="correspondent" as="xs:string" select="."/>
                <xsl:for-each select="$ruth/TEI[correspDesc[correspAction[@type='received']/persName/@key = 'william' and not(correspAction[@type='received']/persName/@key = $corr-main) and correspAction[@type='sent']/persName/@key = $correspondent]]|
                    $ruth/TEI[correspDesc[correspAction[@type='sent']/persName/@key = 'william' and not(correspAction[@type='sent']/persName/@key = $corr-main) and correspAction[@type='received']/persName/@key = $correspondent]]">
                    <TEI correspondence="{$corr-main}">
                        <xsl:apply-templates select="@*|node()"/>
                    </TEI>
                </xsl:for-each>   
                </xsl:for-each>
            </xsl:for-each>
        </root>
    </xsl:template>

    <!-- Identity template : copy all text nodes, elements and attributes -->  
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

, который имеет такой вывод:

<?xml version="1.0" encoding="utf-8"?><root><TEI correspondence="anna" xml:id="1">


<correspDesc>
        <correspAction type="sent">
            <persName key="william"/>
        </correspAction>
        <correspAction type="received">
            <persName key="anna"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="anna" xml:id="2">
    <correspDesc>
        <correspAction type="sent">
            <persName key="anna"/>
        </correspAction>
        <correspAction type="received">
            <persName key="william"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="anna" xml:id="4">
    <correspDesc>
        <correspAction type="sent">
            <persName key="charlotte"/>
            <persName key="anna"/>
        </correspAction>
        <correspAction type="received">
            <persName key="william"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="anna" xml:id="5">
    <correspDesc>
        <correspAction type="sent">
            <persName key="william"/>
            <persName key="charlotte"/>
            <persName key="bertram"/>
        </correspAction>
        <correspAction type="received">
            <persName key="anna"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="anna" xml:id="6">
    <correspDesc>
        <correspAction type="sent">
            <persName key="abraham"/>
            <persName key="anna"/>
        </correspAction>
        <correspAction type="received">
            <persName key="william"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="anna" xml:id="6">
    <correspDesc>
        <correspAction type="sent">
            <persName key="abraham"/>
            <persName key="anna"/>
        </correspAction>
        <correspAction type="received">
            <persName key="william"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="bertram" xml:id="3">
    <correspDesc>
        <correspAction type="sent">
            <persName key="william"/>
        </correspAction>
        <correspAction type="received">
            <persName key="bertram"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI><TEI correspondence="charlotte" xml:id="4">
    <correspDesc>
        <correspAction type="sent">
            <persName key="charlotte"/>
            <persName key="anna"/>
        </correspAction>
        <correspAction type="received">
            <persName key="william"/>
        </correspAction>
    </correspDesc>
    <text/>
</TEI></root>

Вывод неправильный, потому что он дублирует букву 6 (оба принадлежатto корреспонденции = "анна") и не выводит букву 7, хотя она написана Уильямом Шарлотте.Любая идея?Любое упрощение возможно?

1 Ответ

0 голосов
/ 01 февраля 2019

В https://xsltfiddle.liberty -development.net / pPzifp2 / 7 Я пытался сохранить ваши группы корреспонденции в XPath 3.1 array(xs:string*) Например, [('anna', 'abraham'), 'bertram', 'charlotte'] означает, что вы хотите обработать три группы корреспонденции,первое с двумя именами anna и abraham, второе и третье с одним именем (т.е. bertram и charlotte).

Для поиска я использовал ключи для выбора отправителей (<xsl:key name="sent-by" match="TEI" use="correspDesc/correspAction[@type = 'sent']/persName/@key"/>) и получателей (<xsl:key name="received-by" match="TEI" use="correspDesc/correspAction[@type = 'received']/persName/@key"/>), а затем, я думаю, вы можете пересечь каждую группу с ключами с противоположной группой с ключами на william (т.е. пересечь, отправленный, например, "bertram" с полученным "william"):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="persons" as="array(xs:string*)"
     select="[('anna', 'abraham'), 'bertram', 'charlotte']"/>

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

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

  <xsl:key name="sent-by" match="TEI" use="correspDesc/correspAction[@type = 'sent']/persName/@key"/>
  <xsl:key name="received-by" match="TEI" use="correspDesc/correspAction[@type = 'received']/persName/@key"/>

  <xsl:variable name="sent-by-william" select="key('sent-by', 'william')"/>

  <xsl:variable name="received-by-william" select="key('received-by', 'william')"/>

  <xsl:template match="/*">
      <xsl:variable name="root" select="."/>
      <xsl:copy>
          <xsl:for-each select="1 to array:size($persons)">
              <xsl:apply-templates 
                 select="key('sent-by', $persons(.), $root) intersect $received-by-william | 
                         key('received-by', $persons(.), $root) intersect $sent-by-william">
                  <xsl:with-param name="correspondence" select="$persons(.)[1]"/>
              </xsl:apply-templates>
          </xsl:for-each>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="TEI">
      <xsl:param name="correspondence"/>
      <TEI correspondence="{$correspondence}">
          <xsl:apply-templates select="@* | node()"/>
      </TEI>
  </xsl:template>

</xsl:stylesheet>

Это дает результат (как только я исправил элемент xml:id="7", чтобы он имел элемент correspDesc)

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <TEI correspondence="anna" xml:id="1">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
            </correspAction>
            <correspAction type="received">
                <persName key="anna"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="anna" xml:id="2">
        <correspDesc>
            <correspAction type="sent">
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="anna" xml:id="4">
        <correspDesc>
            <correspAction type="sent">
                <persName key="charlotte"/>
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="anna" xml:id="5">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
                <persName key="charlotte"/>
                <persName key="bertram"/>
            </correspAction>
            <correspAction type="received">
                <persName key="anna"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="anna" xml:id="6">
        <correspDesc>
            <correspAction type="sent">
                <persName key="abraham"/>
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="bertram" xml:id="3">
        <correspDesc>
            <correspAction type="sent">
                <persName key="william"/>
            </correspAction>
            <correspAction type="received">
                <persName key="bertram"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="charlotte" xml:id="4">
        <correspDesc>
            <correspAction type="sent">
                <persName key="charlotte"/>
                <persName key="anna"/>
            </correspAction>
            <correspAction type="received">
                <persName key="william"/>
            </correspAction>
        </correspDesc>
        <text/>
    </TEI>
   <TEI correspondence="charlotte" xml:id="7">
        <correspDesc>
            <correspAction type="sent">
                <persName key="abraham"/>
                <persName key="william"/>
            </correspAction>
            <correspAction type="received">
                <persName key="charlotte"/>
            </correspAction>
        </correspDesc>
    </TEI>
</root>

Не уверен, что вы можете использовать XSLT 3 (доступно после Saxon 9.8), ноконечно, легко создать некоторую XML-структуру в XSLT вместо параметра array(xs:string*), как показано в http://xsltransform.net/asnmyG:

  <xsl:param name="person-groups">
      <group>
          <person>anna</person>
          <person>abraham</person>
      </group>
      <group>
          <person>bertram</person>
      </group>
      <group>
          <person>charlotte</person>
      </group>
  </xsl:param>


  <xsl:template match="/*">
      <xsl:variable name="root" select="."/>
      <xsl:copy>
          <xsl:for-each select="$person-groups/group">
              <xsl:apply-templates 
                 select="key('sent-by', person, $root) intersect $received-by-william | 
                         key('received-by', person, $root) intersect $sent-by-william">
                  <xsl:with-param name="correspondence" select="person[1]"/>
              </xsl:apply-templates>
          </xsl:for-each>
      </xsl:copy>
  </xsl:template>

Конечно, как массив XPath 3.1, так и структура XSLT 2 XML могут бытьпостроить из вашего пробела / разделенных тиреПри необходимости выполните последовательность, например, в http://xsltransform.net/asnmyG/1 с

  <xsl:param name="persons">anna-abraham bertram charlotte</xsl:param>

  <xsl:param name="person-groups">
      <xsl:for-each select="tokenize($persons, '\s+')">
          <group>
              <xsl:for-each select="tokenize(., '-')">
                  <person>
                      <xsl:value-of select="."/>
                  </person>
              </xsl:for-each>
          </group>
      </xsl:for-each>
  </xsl:param>

или в https://xsltfiddle.liberty -development.net / pPzifp2 / 8 с

  <xsl:param name="persons-string">anna-abraham bertram charlotte</xsl:param>

  <xsl:param name="persons" as="array(xs:string*)"
     select="array:join(tokenize($persons-string, '\s+') ! [ tokenize(., '-') ])"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...