<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE ... ]>
<abc-config version="THIS" id="abc">
...
</abc-config>
Hi all,
In the code above, how can I extract the value of version attribute using Regex in Groovy/Java?
Thanks.
A regex to handle this could be something like:
/<\?xml version="([0-9.]+)"/
I'll spare you one of the 10000 lectures about not using a regex to parse markup languages.
Edit: The One whose Name cannot be expressed in the Basic Multilingual Plane, He compelled me.
I know you asked for a regex, but what's wrong with this in Groovy?
Assuming the xml is something like:
def xml= '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE abc-config>
<abc-config version="THIS" id="abc">
<node></node>
</abc-config>'''
Then I can parse it with:
def n = new XmlSlurper().parseText( xml )
And then this line:
println n.#version
Prints out "THIS"
If you are having problems with a more complex DOCTYPE failing to load, you can try disabling the DOCTYPE checker by either:
def parser = new XmlSlurper()
parser.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false )
parser.setFeature( "http://xml.org/sax/features/namespaces", false )
parser.parseText( xml )
or by using the constructor for XmlSlurper that takes 2 parameters so as to disable this checking
Not a java regex, Perl regex...
/<\w+\s+[^>]*?(?<=\s)version\s*=\s*["'](.+?)["'][^>]*?\s*\/?>/sg
Note that this fails on many levels, I could fill the page with a proper regex, but I don't have the desire.
this fails too ...
/<\w+\s+[^>]*?(?<=\s)version\s*=\s*(".+?"|'.+?')[^>]*?\s*\/?>/sg
so does this
/<\w+\s+[^>]*?(?<=\s)version\s*=\s*(["'])(.+?)\1[^>]*?\s*\/?>/sg
Related
Recently when i worked with JAXB i had to remove xml header from generated file. I mean, i had to remove first line in xml file which looks like in this way:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
After few minutes i found on internet, that i can use one of this solution:
marshaller.setProperty("jaxb.fragment", true);
or
marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", false);
Both worked for me... but what is difference between them?
NOTE: I'm using Java 12
I created a MCVE which can be found here https://github.com/starwarsjk/jaxb-remove-xml-header
"com.sun.xml.bind.xmlDeclaration" is from JAXB 1 but still supported in JAXB 2.
Marshaller.JAXB_FRAGMENT is equivalent but preferred going forward.
I am trying to create xml file using java. where the expected output is given below
EXPECTED OUTPUT
<?xml version="1.0" encoding="utf-8"?>
<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>2019-112</cbc:ID>
<cbc:IssueDate>2019-01-21</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
</Invoice>
ACTUAL OUTPUT
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ns2="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ns3="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ns4="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</CustomizationID>
<ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ProfileID>
<InvoiceTypeCode>380</InvoiceTypeCode>
</ns4:Invoice>
For clear understanding, lets take "cbc:CustomizationID" in expected output, but in actual output only "CustomizationID"
The actual output is the same as the expected. Just changes how the namespaces are applied.
The XML Parser should treat it exactly the same.
Take a look at XML namespaces.
I have changed the #XmlElement(name = "cbc:CustomizationID", required = true) after generating java class using xjc command. partially issue is solved but needs to change root element to inserted of
We are using ColdFusion and Java to generate the Twilio Markup / XML necessary for handling Twilio calls in our webhook.
Currently, everything works well. The output xml/twiml generated looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+18184461999">
<Number>+18554904999</Number>
</Dial>
</Response>
We generated this markup using java classes in ColdFusion, mainly because ColdFusion can't do it natively. This is the ColdFusion/Java code we currently use to generate the above xml:
<cfscript>
TWILIO_CALLER_ID = "+18184461999";
tophn="+18554904999";
objPattern = CreateObject("java","java.util.regex.Pattern").Compile(JavaCast( "string", "^[\\d\\+\\-\\(\\) ]+$"));
objMatcher=objPattern.Matcher(JavaCast( "string", tophn ));
dialBuilder = createObject("java","com.twilio.twiml.Dial$Builder").init();
dialBuilder.callerId(TWILIO_CALLER_ID);
numberbuilder= createObject("java","com.twilio.twiml.Number$Builder").init(tophn).build();
dialBuilder = dialBuilder.number(numberbuilder);
voiceTwimlResponse = createObject("java","com.twilio.twiml.VoiceResponse$Builder").dial(dialBuilder.build()).build();
response = '<?xml version="1.0" encoding="UTF-8"?>' & voiceTwimlResponse.toXml();
</cfscript>
Everything above works perfectly for our needs.
However, now we would like to add an attribute to the "Dial" element: record="RECORD_FROM_RINGING". Below is what the XML we would like generated would look like:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+18184461999" record="RECORD_FROM_RINGING">
<Number>+18554904999</Number>
</Dial>
</Response>
How would we use ColdFusion + java to accomplish this? We have spent hours trying to figure this out, and nothing works for us. We have looked into the Record and Record$Builder classes, but found nothing that adds this attribute the way we need it. The closest we got to was being able to add a <Record /> element before the <Dial> element, but that does not work for us.
How do we add the attribute record="RECORD_FROM_RINGING" to the <Dial> element using ColdFusion and the appropriate Java classes/objects? All we require is the attribute to be set for that element.
My guess is you are using an older version of the jar which does not support all of the <Dial> attributes. Looks like the Twilio instructions link to an older version (currently 7.0.0). The GitHub version is already up to 7.8.0. Try downloading 7.8.0 or building a newer version from the source (do not forget the dependencies).
The Dial.Builder class in 7.8.0 contains a new method named options(String key, String value) which supports arbitrary attributes. Use it to set the "record" attribute like this:
...
recordOption = createObject("java","com.twilio.twiml.Dial$Record");
dialBuilder.options("record", recordOption.RECORD_FROM_RINGING.toString());
...
** Using the Dial.Record enum, instead of a hard coded string, helps insulate the code against changes in the API.
Result:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+18185551999" record="record-from-ringing">
<Number>+18185554999</Number>
</Dial>
</Response>
I'm trying to merge/combine two xml strings that I got from parsing an object to XML using castor marshalling/unmarshalling. Here are the two XML strings that I have:
<?xml version="1.0" encoding="UTF-8"?>
<abc:abcResponse xmlns:abc="http://www.abc.com/schema/abcTransaction">
<abc:code>0</abc:code>
<abc:description>blah</abc:description>
</abc:abcResponse>
<?xml version="1.0" encoding="UTF-8"?>
<abc:abcRequest xmlns:abc="http://www.abc.com/schema/abcTransaction">
<abc:id>99999</abc:id>
<abc:idString>abc</abc:idString>
</abc:abcRequest>
I want to be able to combine these two strings into one so I can insert this into my database (MSSQL) column that has data type XML. I tried using the solution suggested from this link java merge two xml strings in java, but it doesn't seem to recognize it as a valid XML string since no records were inserted into the database table, and there's this error in my console:
com.microsoft.sqlserver.jdbc.SQLServerException: XML parsing: line 1, character 12, text/xmldecl not at the beginning of input
If I insert either of these strings separately into the database column then a new record will be added just fine.
Anyone has a good idea as to how to do this properly? Much thanks!
You should create something like the following ("abcTransaction" is a wild guess).
<?xml version="1.0" encoding="UTF-8"?>
<abc:abcTransaction xmlns:abc="http://www.abc.com/schema/abcTransaction">
<abc:abcRequest>
<abc:id>99999</abc:id>
<abc:idString>abc</abc:idString>
</abc:abcRequest>
<abc:abcResponse>
<abc:code>0</abc:code>
<abc:description>blah</abc:description>
</abc:abcResponse>
</abc:abcTransaction>
Maybe even leaving out the xmlns and "abc:" parts.
I wish to have a groovy function which can take 2 or more parameters something like input, find_tag.
I wrote something like below to test(not function), but it does not give me D_1164898448. Please help me with it.
def temp="""<Portals objVersion=\"1.1.19\">
<vector xsi:type=\"domainservice:Portals\" objVersion=\"1.1.19\">
<domainName>D_1164898448</domainName>
<address xsi:type=\"metadata:NodeRef\" objVersion=\"1.1.19\">
<host>Komodo</host>
<port>18442</port>
</address>
</vector>
</Portals>"""
def fInput="domainName"
def records = new XmlParser().parseText(temp)
def t=records.findAll{ it.fInput}.text()
println t
Update
for attribute i am doin something like below
println "id = ${records.attribute("id")}"
but like wise how to do it for nodes?
println "host = ${records.vector.address.host.text()}"
If you don't know the exact path to the XML tag you're searching for, you can do something like this to get the content of all tags with the given name:
def t = records."**"."$fInput".text()
To access attributes from a given XML node you can also use the # notation, e.g.
records.vector.#objVersion
What you need to do is:
turn off namespace awareness, so that XmlParser won't throw an error on encountering unbound xsi: prefix. You can do it by passing right arguments to XmlParser constructor.
properly traverse the DOM tree returned by parser - it returns a Node, not a list, and using findAll the way you used will not work
(optionally) remove backslashes from before double quotes in your XML, as escaping double quotes inside a heredoc is not necessary
Your code after corrections:
def temp="""
<Portals objVersion="1.1.19">
<vector xsi:type="domainservice:Portals" objVersion="1.1.19">
<domainName>D_1164898448</domainName>
<address xsi:type="metadata:NodeRef" objVersion="1.1.19">
<host>Komodo</host>
<port>18442</port>
</address>
</vector>
</Portals>
"""
def fInput="domainName"
def records= new XmlParser(false, false).parseText(temp)
def t = records.vector."$fInput".text()
println t
Running it displays 'D_1164898448', as expected.
I'm think you must use XPath expression here, or if you input xml excactly as you show in question, i'm recommend to you regexp like
def temp = ".." //your temp
def m = temp =~ /<domainName>(.*)</domainName>/
print m[0][1] // should be your domain
more about groovy regexp http://groovy.codehaus.org/Regular+Expressions