2015-11-18 4 views
-1

У меня есть текстовый файл со следующими данными:XSLT 2.0 разметить и группа

<t>Heros 
Firstname Sean 
Lastname Connery 
DOB 25-08-1930 

Films 
Dr.No 1962 
Goldfinger 1964 
Thunerball 1965 

Award 
name Academy 
time 1 

Award 
name BAFTA 
time 2 

Award 
name Gloden Globes 
time 3</t> 

Ожидаемый результат должен выглядеть так:

<Jamesfilms> 
    <heros> 
     <firstName>Sean</firstName> 
     <lastName>Connery</lastName> 
     <DOB>25-08-1930</DOB> 
    </heros> 
    <films> 
     <Dr.No>1962</Dr.No> 
     <Goldfinger>1964</Goldfinger> 
     <Thunerball>1965</Thunerball> 
    </films> 
    <award> 
     <name>Academy</name> 
     <times>1</times> 
    </award> 
    <award> 
     <name>BAFTA</name> 
     <times>2</times> 
    </award> 
    <award> 
     <name>Gloden Globes</name> 
     <times>3</times> 
    </award> 
</Jamesfilms> 

содержимого текстового файла являются пространство разделительные пары ключевых значений, как делить значения ключа и сгенерировать узел XML?

EDIT: Я попытался Daniel Haley ответ, и пытается решить ниже исключения:

Error at xsl:for-each on line 10 of transformer.xslt: 
    XTDE1170: Invalid relative URI: Illegal character in path at index 5: 

Java класс:

final String TXT_PATH = "E:/tmp/test/input.txt"; 
    final String XSLT_PATH = "E:/tmp/test/txtToXml.xslt"; 
    final String XML_PATH = "E:/tmp/test/test_xml_result.xml"; 

    TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl(); 
    Transformer transformer = tFactory.newTransformer(new StreamSource(new File(XSLT_PATH))); 
    transformer.transform(new StreamSource(new File(TXT_PATH)),new StreamResult(new File(XML_PATH))); 

и модифицированный XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/> 

    <xsl:variable name="initData" as="node()"> 
    <Jamesfilms> 
     <xsl:for-each select="tokenize(unparsed-text(., $input-encoding),'\r?\n\r?\n')"> 
     <xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/> 
     <xsl:choose> 
      <xsl:when test="$tokens[1] castable as xs:QName"> 
      <xsl:element name="{$tokens[1]}"> 
       <xsl:for-each select="$tokens[position() > 1]"> 
       <xsl:variable name="tokens2" select="tokenize(.,'\s')"/> 
       <xsl:choose> 
        <xsl:when test="$tokens2[1] castable as xs:QName"> 
        <xsl:element name="{$tokens2[1]}"> 
         <xsl:value-of select="$tokens2[position()>1]" separator=" "/> 
        </xsl:element>      
        </xsl:when> 
        <xsl:otherwise> 
        <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message> 
        </xsl:otherwise> 
       </xsl:choose> 
       </xsl:for-each> 
      </xsl:element>    
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:for-each> 
    </Jamesfilms> 
    </xsl:variable> 

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

    <xsl:template match="/"> 
    <xsl:apply-templates select="$initData"/>  
    </xsl:template> 

    <!--Add additional templates to do further transforming of the initial data ($initData).--> 

</xsl:stylesheet> 
+0

@voters, пожалуйста, оставьте комментарий, чтобы я мог улучшить свое СО. – Rembo

+0

Похоже, что весь текстовый файл рассматривается как uri. Какое значение вы задаете для параметра 'input-uri'? Кроме того, я вижу, что вы добавили элемент 't' в текстовый файл (что делает его XML-файлом). Это действительно так? Если так, мой ответ не будет работать как есть. –

+0

@ DanielHaley из значения параметра 'input-uri' класса Java задается как текстовое имя файла. и '' Я добавил, чтобы избежать исключения, например: 'file:/E: /tmp/test/input.txt; lineNumber: 1; columnNumber: 1; Содержимое не разрешено в прологе ' – Rembo

ответ

1

Вы не нужно группировать; вы можете просто tokenize (и tokenize и tokenize ...).

Вот пример. Он ничего не делает с случаем имен элементов. Вы можете обрабатывать эти изменения во время построения $initData, или вы можете добавить дополнительные шаблоны для обработки любых изменений.

Кроме того, имена элементов должны быть действительными QNames. Сейчас таблица стилей завершает обработку сообщением, но вы можете изменить способ обработки.

Это должно, по крайней мере, чтобы вы начали ...

XSLT 2,0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/> 
    <xsl:param name="input-uri" as="xs:string" select="'so.txt'"/> 

    <xsl:variable name="initData" as="node()"> 
    <Jamesfilms> 
     <xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')"> 
     <xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/> 
     <xsl:choose> 
      <xsl:when test="$tokens[1] castable as xs:QName"> 
      <xsl:element name="{$tokens[1]}"> 
       <xsl:for-each select="$tokens[position() > 1]"> 
       <xsl:variable name="tokens2" select="tokenize(.,'\s')"/> 
       <xsl:choose> 
        <xsl:when test="$tokens2[1] castable as xs:QName"> 
        <xsl:element name="{$tokens2[1]}"> 
         <xsl:value-of select="$tokens2[position()>1]" separator=" "/> 
        </xsl:element>      
        </xsl:when> 
        <xsl:otherwise> 
        <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message> 
        </xsl:otherwise> 
       </xsl:choose> 
       </xsl:for-each> 
      </xsl:element>    
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:for-each> 
    </Jamesfilms> 
    </xsl:variable> 

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

    <xsl:template match="/"> 
    <xsl:apply-templates select="$initData"/>  
    </xsl:template> 

    <!--Add additional templates to do further transforming of the initial data ($initData).--> 

</xsl:stylesheet> 

EDIT

можно передать текстовый файл в качестве входного преобразования. Вот почему вам пришлось добавить элемент <t>.

Поскольку у вас фактически нет ввода XML, вы можете передать таблицу стилей в качестве входных данных. Ничто не будет обработано, потому что мы применяем только шаблоны к переменной в шаблоне, который соответствует root (/).

Вам также необходимо установить параметр input-uri с помощью transformer.setParameter("input-uri", TXT_PATH);. Если ваш путь является абсолютным, обязательно добавьте протокол file:///.

Пример ...

Текстовый файл

Heros 
Firstname Sean 
Lastname Connery 
DOB 25-08-1930 

Films 
Dr.No 1962 
Goldfinger 1964 
Thunerball 1965 

Award 
name Academy 
time 1 

Award 
name BAFTA 
time 2 

Award 
name Gloden Globes 
time 3 

Java (вам необходимо изменить пути/имени файла)

final String TXT_PATH = "file:///C:/tmp/input.txt"; 
final String XSLT_PATH = "C:/tmp/txt2xml.xsl"; 
final String XML_PATH = "C:/tmp/test_xml_result.xml"; 

TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl(); 
Transformer transformer = tFactory.newTransformer(new StreamSource(new File(XSLT_PATH))); 
transformer.setParameter("input-uri", TXT_PATH); 
transformer.transform(new StreamSource(new File(XSLT_PATH)),new StreamResult(new File(XML_PATH))); 

XSLT 2.0

То же, что и выше.

Выход

<Jamesfilms> 
    <Heros> 
     <Firstname>Sean</Firstname> 
     <Lastname>Connery</Lastname> 
     <DOB>25-08-1930</DOB> 
    </Heros> 
    <Films> 
     <Dr.No>1962</Dr.No> 
     <Goldfinger>1964</Goldfinger> 
     <Thunerball>1965</Thunerball> 
    </Films> 
    <Award> 
     <name>Academy</name> 
     <time>1</time> 
    </Award> 
    <Award> 
     <name>BAFTA</name> 
     <time>2</time> 
    </Award> 
    <Award> 
     <name>Gloden Globes</name> 
     <time>3</time> 
    </Award> 
</Jamesfilms> 

Однако, так как вы используете Saxon вы можете использовать s9api и указать начальный шаблон. Так я сделал бы это вместо того, чтобы передавать таблицу стилей как вход в преобразование.

Пример ...

Java

final String TXT_PATH = "file:///C:/tmp/input.txt"; 
final String XSLT_PATH = "C:/tmp/txt2xml.xsl"; 
final String XML_PATH = "C:/tmp/test_xml_result.xml"; 

Processor processor = new Processor(false); 
Serializer serializer = processor.newSerializer(); 
serializer.setOutputFile(new File(XML_PATH)); 
XsltCompiler compiler = processor.newXsltCompiler(); 
XsltExecutable executable = compiler.compile(new StreamSource(new File(XSLT_PATH))); 
XsltTransformer transformer = executable.load(); 
transformer.setInitialTemplate(new QName("root")); 
transformer.setParameter(new QName("input-uri"), new XdmAtomicValue(TXT_PATH)); 
transformer.setDestination(serializer); 
transformer.transform(); 

XSLT 2,0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="input-encoding" as="xs:string" select="'iso-8859-1'"/> 
    <xsl:param name="input-uri" as="xs:string"/> 

    <xsl:variable name="initData" as="node()"> 
    <Jamesfilms> 
     <xsl:for-each select="tokenize(unparsed-text($input-uri, $input-encoding),'\r?\n\r?\n')"> 
     <xsl:variable name="tokens" select="tokenize(.,'\r?\n')"/> 
     <xsl:choose> 
      <xsl:when test="$tokens[1] castable as xs:QName"> 
      <xsl:element name="{replace($tokens[1],'\s','')}"> 
       <xsl:for-each select="$tokens[position() > 1]"> 
       <xsl:variable name="tokens2" select="tokenize(.,'\s')"/> 
       <xsl:choose> 
        <xsl:when test="$tokens2[1] castable as xs:QName"> 
        <xsl:element name="{$tokens2[1]}"> 
         <xsl:value-of select="$tokens2[position()>1]" separator=" "/> 
        </xsl:element>      
        </xsl:when> 
        <xsl:otherwise> 
        <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens2[1]"/></xsl:message> 
        </xsl:otherwise> 
       </xsl:choose> 
       </xsl:for-each> 
      </xsl:element>    
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:message terminate="yes">Invalid element name: <xsl:value-of select="$tokens[1]"/></xsl:message> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:for-each> 
    </Jamesfilms> 
    </xsl:variable> 

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

    <xsl:template match="/" name="root"> 
    <xsl:apply-templates select="$initData"/>  
    </xsl:template> 

    <!--Add additional templates to do further transforming of the initial data ($initData).--> 

</xsl:stylesheet> 

Ввод и вывод будет такой же. Дайте мне знать, если вы хотите, чтобы я добавил импорт java к примеру.

+0

Я начал с вашего решения, получаю сообщение, как вы объяснили, есть ли способ сделать имена элементов правильными QNames? – Rembo

+0

вопрос обновлен, пожалуйста, проверьте его – Rembo

+0

@Rembo - Рад, что смогу помочь –

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