Создание XML-файлов с японскими символами с помощью NiFi

#python #apache-nifi

Вопрос:

Я конвертирую полезную нагрузку JSON в XML-файл с помощью процессора Python executeScript в NiFi. JSON выглядит так :

 {
  "Header": {
    "Att1": 1,
    "Att2": "value2",
    "Att3": "1",
    "Att4": "경기00자123"
  }
}
 

Скрипт python для преобразования этого JSON в XML выглядит следующим образом :

 import json
import xml.etree.ElementTree as ET
import java.io
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback

class ModJSON(StreamCallback):

    def __init__(self):
        pass

    def process(self, inputStream, outputStream):
        text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
        data = json.loads(text)
        root = ET.Element("headerinfo")
        entity = ET.SubElement(root, "headerfile")
        ET.SubElement(entity, "Att1").text = str(data["Header"]["Att1"])
        ET.SubElement(entity, "Att2").text = str(data["Header"]["Att2"])
        ET.SubElement(entity, "Att3").text = str(data["Header"]["Att3"])
        ET.SubElement(entity, "Att4").text = data["Header"]["Att4"].encode("utf8")
        xmlNew = ET.tostring(root)
        outputStream.write(bytearray(xmlNew))

flowFile = session.get()
if flowFile != None:
    try :
        flowFile = session.write(flowFile, ModJSON())
        flowFile = session.putAttribute(flowFile, "filename", 'headerfile.xml')
        session.transfer(flowFile, REL_SUCCESS)
        session.commit()
    except Exception as e:
        flowFile = session.putAttribute(flowFile,'python_error', str(e))
        session.transfer(flowFile, REL_FAILURE)
 

Независимо от того, как я пытаюсь закодировать Att4 японскими символами, в результирующем XML это выглядит примерно так :

 amp;#228;amp;#186;amp;#172;amp;#233;amp;#131;amp;#189;111amp;#227;amp;#130;amp;#146;3
 

Как я могу изменить код, чтобы исправить это?
Перепробовал много разных вещей, но, похоже, ничего не работает.

Комментарии:

1. Попробуйте аргументы ElementTree.tostring .. он поддерживает кодировку и режим.

2. @daggett Спасибо за предложение! Попробовал и получил эту ошибку — «write(): 1-й аргумент не может быть преобразован в байт[], int»

3. попробуйте написать(xmlNew.encode(‘utf-8’)) или любую другую кодировку, которую вы использовали для xml.tostring

4. Спасибо за ваши комментарии @daggett Попробовал то, что вы упомянули, это не выдает ошибку, но данные все равно выглядят так : amp;#20140;amp;#37117;111amp;#12434;3

Ответ №1:

похоже, в jython есть проблема со строками байтов-они автоматически преобразуются в объект str с неправильной кодировкой.

однако у ElementTree есть функция записи, которая может записывать в файлоподобный объект, а OutputStream (объект java) фактически реализует функцию записи-таким образом, мы могли бы заставить ElementTree записывать непосредственно в OutputStream

 import json
import xml.etree.ElementTree as ET
from org.apache.commons.io import IOUtils
from java.nio.charset import StandardCharsets
from org.apache.nifi.processor.io import StreamCallback

class ModJSON(StreamCallback):
    def process(self, inputStream, outputStream):
        text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
        data = json.loads(text)
        root = ET.Element("headerinfo")
        entity = ET.SubElement(root, "headerfile")
        ET.SubElement(entity, "Att1").text = str(data["Header"]["Att1"])
        ET.SubElement(entity, "Att2").text = str(data["Header"]["Att2"])
        ET.SubElement(entity, "Att3").text = str(data["Header"]["Att3"])
        ET.SubElement(entity, "Att4").text = data["Header"]["Att4"]
        ET.ElementTree(root).write(outputStream, encoding='utf-8')

flowFile = session.get()
if flowFile != None:
    try :
        flowFile = session.write(flowFile, ModJSON())
        flowFile = session.putAttribute(flowFile, "filename", 'headerfile.xml')
        session.transfer(flowFile, REL_SUCCESS)
        session.commit()
    except Exception as e:
        flowFile = session.putAttribute(flowFile,'python_error', str(e))
        session.transfer(flowFile, REL_FAILURE)
 

Комментарии:

1. Да, это работает! Большое спасибо @dagget