在Java中编辑xml时,更新的xml包含xmlns="”

qni6mghb  于 2023-03-21  发布在  Java
关注(0)|答案(1)|浏览(135)

我有一个xml文件,我需要编辑一些属性的值。当我删除属性并使用新值再次添加相同的属性时,结果包含xmlns=""
初始xml:

<ClinicalDocument xmlns="urn:hl7-org:v3" classCode="DOCCLIN" moodCode="EVN" xmlns:pharm="urn:hl7-org:pharm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <realmCode code="CY"/>
    <typeId extension="POCD_HD000040" root="2.16.840.1.113883.1.3"/>
    <templateId root="1.3.6.1.4.1.12559.11.10.1.3.1.1.2"/>
    <templateId root="1.3.6.1.4.1.19376.1.5.3.1.1.1"/>
    <id extension="1.2.3.4.5.6" root="2.16.840.1.113883.3.9143.3.1.3"/>
    <code code="60593-1" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" codeSystemVersion="2.59" displayName="Medication dispensed.extended Document">
        <translation code="60593-1" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="eDispensation"/>
    </code>
    <title>Medication dispensed</title>
    <effectiveTime value="20221130152655+0000"/>
    <confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25" codeSystemName="Confidentiality" codeSystemVersion="913-20091020" displayName="normal"/>
    <languageCode code="en-GB"/>
    <setId extension="22015711.1" root="2.16.840.1.113883.3.9143.3.1.3"/>
    <recordTarget>
        <patientRole classCode="PAT">
            <id extension="x1x2x2" root="2.16.840.1.113883.2.25.3.4.1.1.2"/>
            <addr>
                <country>GR</country>
                <streetAddressLine>ΕΓΝΑΤΙΑ 10</streetAddressLine>
            </addr>
            <telecom use="H" value="tel:12344"/>
            <patient>
                <name>
                    <given>MARINA</given>
                    <family>FILIP</family>
                </name>
                <administrativeGenderCode code="F" codeSystem="2.16.840.1.113883.5.1" codeSystemName="AdministrativeGender" codeSystemVersion="913-20091020" displayName="Female"/>
                <birthTime value="20150101"/>
                <languageCommunication>
                    <templateId root="1.3.6.1.4.1.19376.1.5.3.1.2.1"/>
                    <languageCode code="en-GB"/>
                </languageCommunication>
            </patient>
        </patientRole>
    </recordTarget>
</ClinicalDocument>

代码:

String eD = "previous_xml_value".
                
DocumentBuilder db = null;
try {
    db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(eD));

Document doc = null;
try {
    doc = db.parse(is);
} catch (SAXException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

// Change info from eD to create eD discard
NodeList node_to_change_code_id_title = doc.getElementsByTagName("ClinicalDocument");
Element element_to_change_code_id_title = null;
NodeList eD_id_to_set_eD_id = null;
Element eD_id_extension = null;

NodeList eD_id_to_set_eD_code = null;
Element eD_set_code = null;
NodeList eD_id_to_set_eD_title = null;
Element eD_set_title = null;

if (node_to_change_code_id_title.getLength()> 0) {
    element_to_change_code_id_title = (Element) node_to_change_code_id_title.item(0);
    
    eD_id_to_set_eD_id = element_to_change_code_id_title.getElementsByTagName("id");
    eD_id_extension = (Element) eD_id_to_set_eD_id.item(0);
    eD_id_extension.removeAttribute("extension");
    eD_id_extension.setAttribute("extension", discard_eD_id_full);
    
    eD_id_to_set_eD_code = element_to_change_code_id_title.getElementsByTagName("code");
    eD_set_code = (Element) eD_id_to_set_eD_code.item(0);
    eD_set_code.setAttribute("xmlns", "urn:hl7-org:v3");
    eD_set_code.removeAttribute("code");
    eD_set_code.setAttribute("code", "DISCARD-60593-1");
    eD_set_code.removeAttribute("codeSystem");
    eD_set_code.setAttribute("codeSystem", "2.16.840.1.113883.6.1");
    eD_set_code.removeAttribute("codeSystemName");
    eD_set_code.setAttribute("codeSystemName", "LOINC");
    eD_set_code.removeAttribute("displayName");
    eD_set_code.setAttribute("displayName", "Discard Medication Dispensed");
    
    eD_id_to_set_eD_title = element_to_change_code_id_title.getElementsByTagName("title");
    eD_set_title = (Element) eD_id_to_set_eD_title.item(0);
    eD_set_title.setTextContent("Discard Medication Dispensed");
}

这就是结果:

<ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:pharm="urn:hl7-org:pharm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" classCode="DOCCLIN" moodCode="EVN">
    <realmCode xmlns="" code="CY"/>
    <typeId xmlns="" extension="POCD_HD000040" root="2.16.840.1.113883.1.3"/>
    <templateId xmlns="" root="1.3.6.1.4.1.12559.11.10.1.3.1.1.2"/>
    <templateId xmlns="" root="1.3.6.1.4.1.19376.1.5.3.1.1.1"/>
    <id extension="eDDiscId.CY202303170000002" root="2.16.840.1.113883.3.9143.3.1.3"/>
    <code code="DISCARD-60593-1" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" codeSystemVersion="2.59" displayName="Discard Medication Dispensed">
        <translation xmlns="" code="60593-1" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="eDispensation"/>
    </code>
    <title xmlns="">Discard Medication Dispensed</title>
    <effectiveTime xmlns="" value="20221130152655+0000"/>
    <confidentialityCode xmlns="" code="N" codeSystem="2.16.840.1.113883.5.25" codeSystemName="Confidentiality" codeSystemVersion="913-20091020" displayName="normal"/>
    <languageCode xmlns="" code="en-GB"/>
    <setId xmlns="" extension="22015711.1" root="2.16.840.1.113883.3.9143.3.1.3"/>
    <recordTarget xmlns="">
        <patientRole classCode="PAT">
            <id extension="x1x2x2" root="2.16.840.1.113883.2.25.3.4.1.1.2"/>
            <addr>
                <country>GR</country>
                <streetAddressLine>ΕΓΝΑΤΙΑ 10</streetAddressLine>
            </addr>
            <telecom use="H" value="tel:12344"/>
            <patient>
                <name>
                    <given>MARINA</given>
                    <family>FILIP</family>
                </name>
                <administrativeGenderCode code="F" codeSystem="2.16.840.1.113883.5.1" codeSystemName="AdministrativeGender" codeSystemVersion="913-20091020" displayName="Female"/>
                <birthTime value="20150101"/>
                <languageCommunication>
                    <templateId root="1.3.6.1.4.1.19376.1.5.3.1.2.1"/>
                    <languageCode code="en-GB"/>
                </languageCommunication>
            </patient>
        </patientRole>
    </recordTarget>
</ClinicalDocument>
velaa5lx

velaa5lx1#

您的输出取决于您生成输出的方式。Document对象是XML文档的内存表示。使用JAXP API,您解析XML以创建Document对象,然后迭代Nodes并根据您的需求修改内存中的Elements
输出XML是从内存中修改的Document对象生成XML的结果。
生成输出的缺失部分对您看到的输出也有重要作用,因为输出的某些方面可以配置。如果您正在处理JAXP API,则可以通过以下代码片段实现。我将其作为将XML输出打印到控制台的方法,但这可以根据需要进行调整。这不会生成xmlns属性。
我已经通过使用下面的方法打印输出测试了你的代码,它在输出中没有xmlns属性。

static void printDoc(Document doc)  throws  Exception{
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");

        Writer out = new StringWriter();
        transformer.transform(new DOMSource(doc), new StreamResult(out));

        System.out.println(out.toString());
    }

话虽如此,我建议你使用XSLT为你的用例,如果它是一个项目,这并不要求你使用Document对象来执行你的转换。可能你必须学习XSLT,但这是一个正确的工具,你正在努力实现。你可以在互联网上找到很多帮助,开始使用XSLT。
下面是一个如何将转换转换到XSLT中的例子,其中Map(或转换)了一些元素,但您可以根据需要对此进行扩展。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsL="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <!-- This is called an identity template, which means it copies all XML elements and attributes as it is into output XML -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="title">
        <xsl:copy>
            <xsl:text>Discard Medication Dispensed</xsl:text>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="code/@code">
        <xsl:attribute name="{name()}">
            <xsl:value-of select="concat('DISAORD-', .)"/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="code/@displayName">
        <xsl:attribute name="{name()}">
            <xsl:text>Discard Medication Dispensed</xsl:text>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

正如您所看到的,转换被定义为匹配节点和属性的模板。templatematch属性定义了此转换将应用于输入XML的哪些元素。
这里需要理解的基本内容有:如何引用节点或XML元素,以及如何引用属性等(还有什么其他的?你甚至可以引用输入XML中的注解,但现在不要太担心)。
第一个模板(称为identity template)表示对于任何node()或称为@*的属性,复制该元素并为子元素应用其他匹配模板。如果没有定义其他模板,则该模板作为递归模板(概念上理解),最终将所有输入复制到输出,这就是名称identity template的原因。
但是,如果您定义了与输入XML中的特定元素匹配的其他模板,那么它们将优先,因此您可以告诉对特定匹配元素应用什么转换。这就是下一个简单模板的作用。

<xsl:template match="title">
        <xsl:copy>
            <xsl:text>Discard Medication Dispensed</xsl:text>
        </xsl:copy>
    </xsl:template>

匹配输入文档中的title节点或XML元素,转换为,

  • 复制元素名称
  • 但将文本更改为Discard Medication Dispensed

下一个模板有一点变化

<xsl:template match="code/@code">
        <xsl:attribute name="{name()}">
            <xsl:value-of select="concat('DISAORD-', .)"/>
        </xsl:attribute>
    </xsl:template>

这将匹配节点code的属性code(基本上是<code code='60593-1' ....>。将应用模板中定义的转换。根据您在Document对象操作中所做的操作,这实际上已经预先添加了DISCARD-。因此我使用了concat函数。因此此模板表示

  • 原样复制属性名({name()},此处指属性名)
  • 连接DISCARD-和input中的值(由.引用)

类似地,下一个模板<xsl:template match="code/@displayName">,定义相同code节点的转换,但针对displayName属性。
有一点很重要,matchXPath值适用于XML中匹配的所有元素。例如,模板<xsl:template match="title">适用于层次结构中XML中任何位置的任何XML元素title。因为在特定的输入XML中,它只出现一次,并且是根元素ClinicalDocument的子元素,所以它在这里按预期工作。如果您在输入XML的另一部分中有title,则此模板也将应用于title。在这种情况下,如果这不是故意的,则相应地构建XPath以引用特定元素,例如include parent/title,因此这引用parent元素下的title子元素。根据输入XML结构,这可以是简单的,也可以是复杂的。2这种复杂性来自输入XML结构,而不是因为使用XSLT。
您可能已经理解了,XML元素的名称为<code ....>,如code,属性的前缀为@,如@displayName。斜杠的使用类似于磁盘上的文件路径。在XML世界中,它被称为XPath。如果您能够掌握XML文档元素的层次结构或父子结构,则可以使用@。(我的意思是节点、属性、文本等),然后将输入XML中特定部分的路径定义为XPath。
基于您已经在Java代码级别使用ElementAttribute等在Document对象中导航,我想您可以在头脑中将XMLMap为层次结构,在XPath中引用XML的一部分应该不是那么困难。

这个XSLT是如何插入到代码中的:

非常简单,基本上与printDoc方法中的步骤相同,但是转换器是用XSLT创建的,而不是空的转换器(这里的空是指TransformerFactory.newInstance().newTransformer(),没有newTransformer方法的参数)。所以,这将更改为TransformerFactory.newInstance().newTransformer(new StreamSource(new File("path/to/xslt/file/dir/my-clinical-transformer.xslt")));,假设XSLT是一个包含上述模板定义的单独文件。StreamSource有不同的构造函数,它们采用不同类型的参数。如果需要使用不同的方法,您可以制定如何使用它们。
简而言之,您可以用下面的方法调用替换转换Java代码。

static void xsltTrans(Document doc)  throws  Exception{
        Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new File("src/com/mad/test/xml/trans.xslt")));

        Writer out = new StringWriter();
        transformer.transform(new DOMSource(doc), new StreamResult(out));

        System.out.println(out.toString());
    }

doc参数是通过使用DocumentBuilder解析输入XML创建的Document对象。如果您已经注意到,在Java代码中,transformer的输出属性被删除了,因为它们在XSLT中被指定为<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
仅供参考,xmlns表示XML世界中的名称空间,有点像Java中的包。我猜您并不担心这一点,因为您希望消除xmlns,这是可以的。
希望这能有所帮助!

相关问题